Refactor done

This commit is contained in:
ef3d0c3e 2024-08-06 18:58:41 +02:00
parent 84e4c17fda
commit ce9effd465
32 changed files with 459 additions and 508 deletions

View file

@ -1,23 +1,24 @@
use std::{cell::RefCell, rc::Rc}; use std::cell::RefCell;
use std::rc::Rc;
use crate::parser::source::Source; use crate::parser::source::Source;
use super::{document::{Document, Scope}, element::Element}; use super::document::Document;
use super::document::Scope;
use super::element::Element;
#[derive(Debug)] #[derive(Debug)]
pub struct LangDocument<'a> { pub struct LangDocument<'a> {
source: Rc<dyn Source>, source: Rc<dyn Source>,
parent: Option<&'a dyn Document<'a>>, /// Document's parent parent: Option<&'a dyn Document<'a>>,
/// Document's parent
// FIXME: Render these fields private // FIXME: Render these fields private
pub content: RefCell<Vec<Box<dyn Element>>>, pub content: RefCell<Vec<Box<dyn Element>>>,
pub scope: RefCell<Scope>, pub scope: RefCell<Scope>,
} }
impl<'a> LangDocument<'a> impl<'a> LangDocument<'a> {
{ pub fn new(source: Rc<dyn Source>, parent: Option<&'a dyn Document<'a>>) -> Self {
pub fn new(source: Rc<dyn Source>, parent: Option<&'a dyn Document<'a>>) -> Self
{
Self { Self {
source: source, source: source,
parent: parent, parent: parent,
@ -28,11 +29,13 @@ impl<'a> LangDocument<'a>
} }
impl<'a> Document<'a> for LangDocument<'a> { impl<'a> Document<'a> for LangDocument<'a> {
fn source(&self) -> Rc<dyn Source> { self.source.clone() } fn source(&self) -> Rc<dyn Source> { self.source.clone() }
fn parent(&self) -> Option<&'a dyn Document<'a>> { self.parent.and_then(|p| Some(p as &dyn Document<'a>)) } fn parent(&self) -> Option<&'a dyn Document<'a>> {
self.parent.and_then(|p| Some(p as &dyn Document<'a>))
}
fn content(&self) -> &RefCell<Vec<Box<dyn Element>>> { &self.content } fn content(&self) -> &RefCell<Vec<Box<dyn Element>>> { &self.content }
fn scope(&self) -> &RefCell<Scope> { &self.scope } fn scope(&self) -> &RefCell<Scope> { &self.scope }
} }

View file

@ -45,6 +45,7 @@ pub mod tests {
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser; use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::ParserState;
#[test] #[test]
fn validate_refname_tests() { fn validate_refname_tests() {
@ -54,7 +55,7 @@ pub mod tests {
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let doc = parser.parse(source, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
assert_eq!(validate_refname(&*doc, " abc ", true), Ok("abc")); assert_eq!(validate_refname(&*doc, " abc ", true), Ok("abc"));
assert_eq!( assert_eq!(

View file

@ -1,6 +1,5 @@
use super::document::Document; use super::document::Document;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::source::Source; use crate::parser::source::Source;
use crate::parser::source::Token; use crate::parser::source::Token;
@ -19,7 +18,7 @@ pub trait Variable {
/// Converts variable to a string /// Converts variable to a string
fn to_string(&self) -> String; fn to_string(&self) -> String;
fn parse<'a>(&self, state: &mut ParserState, location: Token, document: &'a dyn Document<'a>); fn parse<'a>(&self, state: &ParserState, location: Token, document: &'a dyn Document<'a>);
} }
impl core::fmt::Debug for dyn Variable { impl core::fmt::Debug for dyn Variable {
@ -57,7 +56,7 @@ impl Variable for BaseVariable {
fn to_string(&self) -> String { self.value.clone() } fn to_string(&self) -> String { self.value.clone() }
fn parse<'a>(&self, state: &mut ParserState, _location: Token, document: &'a dyn Document<'a>) { fn parse<'a>(&self, state: &ParserState, _location: Token, document: &'a dyn Document<'a>) {
let source = Rc::new(VirtualSource::new( let source = Rc::new(VirtualSource::new(
self.location().clone(), self.location().clone(),
self.name().to_string(), self.name().to_string(),
@ -97,14 +96,14 @@ impl Variable for PathVariable {
fn to_string(&self) -> String { self.path.to_str().unwrap().to_string() } fn to_string(&self) -> String { self.path.to_str().unwrap().to_string() }
fn parse<'a>(&self, state: &mut ParserState, location: Token, document: &'a dyn Document) { fn parse<'a>(&self, state: &ParserState, location: Token, document: &'a dyn Document) {
let source = Rc::new(VirtualSource::new( let source = Rc::new(VirtualSource::new(
location, location,
self.name().to_string(), self.name().to_string(),
self.to_string(), self.to_string(),
)); ));
state.parser.push( state.push(
document, document,
Box::new(Text::new( Box::new(Text::new(
Token::new(0..source.content().len(), source), Token::new(0..source.content().len(), source),

View file

@ -25,7 +25,6 @@ use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -324,7 +323,7 @@ impl CodeRule {
) )
.unwrap(), .unwrap(),
], ],
properties: PropertyParser{ properties: props }, properties: PropertyParser { properties: props },
} }
} }
} }
@ -337,7 +336,7 @@ impl RegexRule for CodeRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
index: usize, index: usize,
state: &mut ParserState, state: &ParserState,
document: &'a dyn Document, document: &'a dyn Document,
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -505,7 +504,7 @@ impl RegexRule for CodeRule {
} }
}; };
state.parser.push( state.push(
document, document,
Box::new(Code::new( Box::new(Code::new(
token.clone(), token.clone(),
@ -526,7 +525,7 @@ impl RegexRule for CodeRule {
CodeKind::Inline CodeKind::Inline
}; };
state.parser.push( state.push(
document, document,
Box::new(Code::new( Box::new(Code::new(
token.clone(), token.clone(),
@ -555,7 +554,7 @@ impl RegexRule for CodeRule {
.get_variable("code.theme") .get_variable("code.theme")
.and_then(|var| Some(var.to_string())); .and_then(|var| Some(var.to_string()));
ctx.parser.push( ctx.state.push(
ctx.document, ctx.document,
Box::new(Code { Box::new(Code {
location: ctx.location.clone(), location: ctx.location.clone(),
@ -586,7 +585,7 @@ impl RegexRule for CodeRule {
.get_variable("code.theme") .get_variable("code.theme")
.and_then(|var| Some(var.to_string())); .and_then(|var| Some(var.to_string()));
ctx.parser.push( ctx.state.push(
ctx.document, ctx.document,
Box::new(Code { Box::new(Code {
location: ctx.location.clone(), location: ctx.location.clone(),
@ -624,7 +623,7 @@ impl RegexRule for CodeRule {
.get_variable("code.theme") .get_variable("code.theme")
.and_then(|var| Some(var.to_string())); .and_then(|var| Some(var.to_string()));
ctx.parser.push( ctx.state.push(
ctx.document, ctx.document,
Box::new(Code { Box::new(Code {
location: ctx.location.clone(), location: ctx.location.clone(),
@ -653,6 +652,7 @@ impl RegexRule for CodeRule {
mod tests { mod tests {
use super::*; use super::*;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
#[test] #[test]
@ -726,8 +726,7 @@ fn fact(n: usize) -> usize
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
//let compiler = Compiler::new(Target::HTML, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
let doc = parser.parse(source, None);
let borrow = doc.content().borrow(); let borrow = doc.content().borrow();
let found = borrow let found = borrow

View file

@ -2,7 +2,6 @@ use crate::compiler::compiler::Compiler;
use crate::document::document::Document; use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -59,7 +58,7 @@ impl RegexRule for CommentRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
state: &mut ParserState, state: &ParserState,
document: &'a dyn Document, document: &'a dyn Document,
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -87,7 +86,13 @@ impl RegexRule for CommentRule {
} }
}; };
state.parser.push(document, Box::new(Comment::new(token.clone(), content))); state.push(
document,
Box::new(Comment {
location: token.clone(),
content,
}),
);
return reports; return reports;
} }
@ -96,9 +101,10 @@ impl RegexRule for CommentRule {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::elements::paragraph::Paragraph; use crate::elements::paragraph::Paragraph;
use crate::elements::style::Style; use crate::elements::style::Style;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;

View file

@ -1,4 +1,6 @@
use crate::lua::kernel::Kernel;
use std::any::Any; use std::any::Any;
use std::cell::Ref;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Range; use std::ops::Range;
@ -19,7 +21,6 @@ use crate::lua::kernel::KernelContext;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::customstyle::CustomStyle; use crate::parser::customstyle::CustomStyle;
use crate::parser::customstyle::CustomStyleToken; use crate::parser::customstyle::CustomStyleToken;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::Rule; use crate::parser::rule::Rule;
use crate::parser::source::Cursor; use crate::parser::source::Cursor;
@ -28,8 +29,6 @@ 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 lazy_static::lazy_static;
use super::paragraph::Paragraph; use super::paragraph::Paragraph;
#[derive(Debug)] #[derive(Debug)]
@ -48,75 +47,78 @@ impl CustomStyle for LuaCustomStyle {
fn on_start<'a>( fn on_start<'a>(
&self, &self,
location: Token, location: Token,
parser_state: &mut ParserState, state: &ParserState,
document: &'a dyn Document<'a>, document: &'a dyn Document<'a>,
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
let kernel = parser_state.shared.kernels.get("main").unwrap(); let kernel: Ref<'_, Kernel> =
Ref::map(state.shared.kernels.borrow(), |b| b.get("main").unwrap());
//let kernel = RefMut::map(parser_state.shared.kernels.borrow(), |ker| ker.get("main").unwrap());
let ctx = KernelContext { let ctx = KernelContext {
location: location.clone(), location: location.clone(),
parser_state, state,
document, document,
}; };
let mut result = Ok(()); let mut reports = vec![];
kernel.run_with_context(ctx, |lua| { kernel.run_with_context(ctx, |lua| {
let chunk = lua.load(self.start.as_str()); let chunk = lua.load(self.start.as_str());
if let Err(err) = chunk.eval::<()>() { if let Err(err) = chunk.eval::<()>() {
result = Err( reports.push(
Report::build(ReportKind::Error, location.source(), location.start()) Report::build(ReportKind::Error, location.source(), location.start())
.with_message("Lua execution failed") .with_message("Lua execution failed")
.with_label( .with_label(
Label::new((location.source(), location.range.clone())) Label::new((location.source(), location.range.clone()))
.with_message(err.to_string()) .with_message(err.to_string())
.with_color(parser_state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.with_note(format!( .with_note(format!(
"When trying to start custom style {}", "When trying to start custom style {}",
self.name().fg(parser_state.parser.colors().info) self.name().fg(state.parser.colors().info)
)) ))
.finish(), .finish(),
); );
} }
}); });
result reports
} }
fn on_end<'a>( fn on_end<'a>(
&self, &self,
location: Token, location: Token,
parser_state: &mut ParserState, state: &ParserState,
document: &'a dyn Document<'a> document: &'a dyn Document<'a>,
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
let kernel = parser_state.shared.kernels.get("main").unwrap(); let kernel: Ref<'_, Kernel> =
Ref::map(state.shared.kernels.borrow(), |b| b.get("main").unwrap());
let ctx = KernelContext { let ctx = KernelContext {
location: location.clone(), location: location.clone(),
parser_state, state,
document, document,
}; };
let mut result = Ok(()); let mut reports = vec![];
kernel.run_with_context(ctx, |lua| { kernel.run_with_context(ctx, |lua| {
let chunk = lua.load(self.end.as_str()); let chunk = lua.load(self.end.as_str());
if let Err(err) = chunk.eval::<()>() { if let Err(err) = chunk.eval::<()>() {
result = Err( reports.push(
Report::build(ReportKind::Error, location.source(), location.start()) Report::build(ReportKind::Error, location.source(), location.start())
.with_message("Lua execution failed") .with_message("Lua execution failed")
.with_label( .with_label(
Label::new((location.source(), location.range.clone())) Label::new((location.source(), location.range.clone()))
.with_message(err.to_string()) .with_message(err.to_string())
.with_color(parser_state.colors().error), .with_color(state.parser.colors().error),
) )
.with_note(format!( .with_note(format!(
"When trying to end custom style {}", "When trying to end custom style {}",
self.name().fg(parser_state.colors().info) self.name().fg(state.parser.colors().info)
)) ))
.finish(), .finish(),
); );
} }
}); });
result reports
} }
} }
@ -129,8 +131,8 @@ impl RuleState for CustomStyleState {
fn on_remove<'a>( fn on_remove<'a>(
&self, &self,
state: &mut ParserState, state: &ParserState,
document: &dyn Document document: &dyn Document,
) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>> {
let mut reports = vec![]; let mut reports = vec![];
@ -189,6 +191,7 @@ impl Rule for CustomStyleRule {
state state
.shared .shared
.custom_styles .custom_styles
.borrow()
.iter() .iter()
.for_each(|(_name, style)| match style.tokens() { .for_each(|(_name, style)| match style.tokens() {
CustomStyleToken::Toggle(s) => { CustomStyleToken::Toggle(s) => {
@ -228,67 +231,61 @@ impl Rule for CustomStyleRule {
fn on_match<'a>( fn on_match<'a>(
&self, &self,
state: &mut ParserState, state: &ParserState,
document: &'a dyn Document<'a>, document: &'a dyn Document<'a>,
cursor: Cursor, cursor: Cursor,
match_data: Option<Box<dyn Any>>, match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) { ) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
let (style, end) = match_data let (style, end) = match_data
.as_ref()
.unwrap()
.downcast_ref::<(Rc<dyn CustomStyle>, bool)>() .downcast_ref::<(Rc<dyn CustomStyle>, bool)>()
.unwrap(); .unwrap();
let query = state.shared.rule_state.get(STATE_NAME); let mut rule_state_borrow = state.shared.rule_state.borrow_mut();
let rule_state = match query { let style_state = match rule_state_borrow.get(STATE_NAME) {
Some(state) => state, Some(rule_state) => rule_state,
// Insert as a new state
None => { None => {
// Insert as a new state match rule_state_borrow.insert(
match state.shared.rule_state.insert(
STATE_NAME.into(), STATE_NAME.into(),
Rc::new(RefCell::new(CustomStyleState { Rc::new(RefCell::new(CustomStyleState {
toggled: HashMap::new(), toggled: HashMap::new(),
})), })),
) { ) {
Err(_) => panic!("Unknown error"), Err(err) => panic!("{err}"),
Ok(state) => state, Ok(rule_state) => rule_state,
} }
} }
}; };
let (close, token) = match style.tokens() { let (close, token) = match style.tokens() {
CustomStyleToken::Toggle(s) => { CustomStyleToken::Toggle(s) => {
let mut borrow = rule_state.borrow_mut(); let mut borrow = style_state.as_ref().borrow_mut();
let state = borrow.downcast_mut::<CustomStyleState>().unwrap(); let style_state = borrow.downcast_mut::<CustomStyleState>().unwrap();
match state.toggled.get(style.name()) { if style_state.toggled.get(style.name()).is_some() {
Some(_) => { // Terminate style
// Terminate style let token = Token::new(cursor.pos..cursor.pos + s.len(), cursor.source.clone());
let token =
Token::new(cursor.pos..cursor.pos + s.len(), cursor.source.clone());
state.toggled.remove(style.name()); style_state.toggled.remove(style.name());
(true, token) (true, token)
} } else {
None => { // Start style
// Start style let token = Token::new(cursor.pos..cursor.pos + s.len(), cursor.source.clone());
let token =
Token::new(cursor.pos..cursor.pos + s.len(), cursor.source.clone());
state.toggled.insert(style.name().into(), token.clone()); style_state
(false, token) .toggled
} .insert(style.name().into(), token.clone());
(false, token)
} }
} }
CustomStyleToken::Pair(s_begin, s_end) => { CustomStyleToken::Pair(s_begin, s_end) => {
let mut borrow = rule_state.borrow_mut(); let mut borrow = style_state.borrow_mut();
let state = borrow.downcast_mut::<CustomStyleState>().unwrap(); let style_state = borrow.downcast_mut::<CustomStyleState>().unwrap();
if *end { if *end {
// Terminate style // Terminate style
let token = let token =
Token::new(cursor.pos..cursor.pos + s_end.len(), cursor.source.clone()); Token::new(cursor.pos..cursor.pos + s_end.len(), cursor.source.clone());
if state.toggled.get(style.name()).is_none() { if style_state.toggled.get(style.name()).is_none() {
return ( return (
cursor.at(cursor.pos + s_end.len()), cursor.at(cursor.pos + s_end.len()),
vec![ vec![
@ -308,7 +305,7 @@ impl Rule for CustomStyleRule {
); );
} }
state.toggled.remove(style.name()); style_state.toggled.remove(style.name());
(true, token) (true, token)
} else { } else {
// Start style // Start style
@ -316,7 +313,7 @@ impl Rule for CustomStyleRule {
cursor.pos..cursor.pos + s_begin.len(), cursor.pos..cursor.pos + s_begin.len(),
cursor.source.clone(), cursor.source.clone(),
); );
if let Some(start_token) = state.toggled.get(style.name()) { if let Some(start_token) = style_state.toggled.get(style.name()) {
return ( return (
cursor.at(cursor.pos + s_end.len()), cursor.at(cursor.pos + s_end.len()),
vec![Report::build( vec![Report::build(
@ -347,27 +344,23 @@ impl Rule for CustomStyleRule {
); );
} }
state.toggled.insert(style.name().into(), token.clone()); style_state
.toggled
.insert(style.name().into(), token.clone());
(false, token) (false, token)
} }
} }
}; };
if let Err(rep) = if close { let reports = if close {
style.on_end(token.clone(), state, document) style.on_end(token.clone(), state, document)
} else { } else {
style.on_start(token.clone(), state, document) style.on_start(token.clone(), state, document)
} { };
return (
cursor.at(token.end()), (cursor.at(token.end()), unsafe {
vec![unsafe { std::mem::transmute(reports)
// TODO })
std::mem::transmute(rep)
}],
);
} else {
(cursor.at(token.end()), vec![])
}
} }
fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
@ -388,7 +381,9 @@ impl Rule for CustomStyleRule {
CTX.with_borrow(|ctx| { CTX.with_borrow(|ctx| {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
if let Some(_) = ctx.state.shared.custom_styles.get(name.as_str()) { if let Some(_) =
ctx.state.shared.custom_styles.borrow().get(name.as_str())
{
result = Err(BadArgument { result = Err(BadArgument {
to: Some("define_toggled".to_string()), to: Some("define_toggled".to_string()),
pos: 1, pos: 1,
@ -399,7 +394,11 @@ impl Rule for CustomStyleRule {
}); });
return; return;
} }
ctx.state.shared.custom_styles.insert(Rc::new(style)); ctx.state
.shared
.custom_styles
.borrow_mut()
.insert(Rc::new(style));
}); });
}); });
@ -443,7 +442,7 @@ impl Rule for CustomStyleRule {
CTX.with_borrow(|ctx| { CTX.with_borrow(|ctx| {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
if let Some(_) = ctx.state.shared.custom_styles.get(name.as_str()) { if let Some(_) = ctx.state.shared.custom_styles.borrow().get(name.as_str()) {
result = Err(BadArgument { result = Err(BadArgument {
to: Some("define_paired".to_string()), to: Some("define_paired".to_string()),
pos: 1, pos: 1,
@ -454,7 +453,7 @@ impl Rule for CustomStyleRule {
}); });
return; return;
} }
ctx.state.shared.custom_styles.insert(Rc::new(style)); ctx.state.shared.custom_styles.borrow_mut().insert(Rc::new(style));
}); });
}); });
@ -473,6 +472,7 @@ mod tests {
use crate::elements::raw::Raw; use crate::elements::raw::Raw;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;
@ -505,7 +505,7 @@ pre |styled| post °Hello°.
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let doc = parser.parse(source, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {
@ -549,7 +549,7 @@ pre [styled] post (Hello).
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let doc = parser.parse(source, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {

View file

@ -1,3 +1,4 @@
use crate::parser::style::ElementStyle;
use std::any::Any; use std::any::Any;
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
@ -15,7 +16,6 @@ use regex::Regex;
use crate::document::document::Document; use crate::document::document::Document;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::Rule; use crate::parser::rule::Rule;
use crate::parser::source::Cursor; use crate::parser::source::Cursor;
@ -69,10 +69,10 @@ impl Rule for ElemStyleRule {
fn on_match<'a>( fn on_match<'a>(
&self, &self,
state: &mut ParserState, state: &ParserState,
_document: &'a (dyn Document<'a> + 'a), _document: &'a (dyn Document<'a> + 'a),
cursor: Cursor, cursor: Cursor,
_match_data: Option<Box<dyn Any>>, _match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) { ) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
let mut reports = vec![]; let mut reports = vec![];
let matches = self let matches = self
@ -81,7 +81,7 @@ impl Rule for ElemStyleRule {
.unwrap(); .unwrap();
let mut cursor = cursor.at(matches.get(0).unwrap().end() - 1); let mut cursor = cursor.at(matches.get(0).unwrap().end() - 1);
let style = if let Some(key) = matches.get(1) { let style: Rc<dyn ElementStyle> = if let Some(key) = matches.get(1) {
let trimmed = key.as_str().trim_start().trim_end(); let trimmed = key.as_str().trim_start().trim_end();
// Check if empty // Check if empty
@ -100,7 +100,7 @@ impl Rule for ElemStyleRule {
} }
// Check if key exists // Check if key exists
if !state.shared.style.is_registered(trimmed) { if !state.shared.styles.borrow().is_registered(trimmed) {
reports.push( reports.push(
Report::build(ReportKind::Error, cursor.source.clone(), key.start()) Report::build(ReportKind::Error, cursor.source.clone(), key.start())
.with_message("Unknown Style Key") .with_message("Unknown Style Key")
@ -118,7 +118,7 @@ impl Rule for ElemStyleRule {
return (cursor, reports); return (cursor, reports);
} }
state.shared.style.current_style(trimmed) state.shared.styles.borrow().current(trimmed)
} else { } else {
panic!("Unknown error") panic!("Unknown error")
}; };
@ -172,7 +172,7 @@ impl Rule for ElemStyleRule {
} }
}; };
state.shared.styles.set_current(new_style); state.shared.styles.borrow_mut().set_current(new_style);
(cursor, reports) (cursor, reports)
} }
@ -186,7 +186,13 @@ impl Rule for ElemStyleRule {
let mut result = Ok(()); let mut result = Ok(());
CTX.with_borrow(|ctx| { CTX.with_borrow(|ctx| {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
if !ctx.parser.is_style_registered(style_key.as_str()) { if !ctx
.state
.shared
.styles
.borrow()
.is_registered(style_key.as_str())
{
result = Err(BadArgument { result = Err(BadArgument {
to: Some("set".to_string()), to: Some("set".to_string()),
pos: 1, pos: 1,
@ -198,7 +204,7 @@ impl Rule for ElemStyleRule {
return; return;
} }
let style = ctx.parser.current_style(style_key.as_str()); let style = ctx.state.shared.styles.borrow().current(style_key.as_str());
let new_style = match style.from_lua(lua, new_style) { let new_style = match style.from_lua(lua, new_style) {
Err(err) => { Err(err) => {
result = Err(err); result = Err(err);
@ -207,7 +213,7 @@ impl Rule for ElemStyleRule {
Ok(new_style) => new_style, Ok(new_style) => new_style,
}; };
ctx.parser.set_current_style(new_style); ctx.state.shared.styles.borrow_mut().set_current(new_style);
}) })
}); });

View file

@ -16,8 +16,6 @@ use crypto::sha2::Sha512;
use graphviz_rust::cmd::Format; use graphviz_rust::cmd::Format;
use graphviz_rust::cmd::Layout; use graphviz_rust::cmd::Layout;
use graphviz_rust::exec_dot; use graphviz_rust::exec_dot;
use mlua::Function;
use mlua::Lua;
use regex::Captures; use regex::Captures;
use regex::Regex; use regex::Regex;
@ -28,7 +26,6 @@ use crate::compiler::compiler::Target;
use crate::document::document::Document; use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::parser::parser::Parser;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
use crate::parser::source::Token; use crate::parser::source::Token;
@ -71,7 +68,7 @@ impl Graphviz {
let split_at = out.split_at(svg_start).1.find('\n').unwrap(); let split_at = out.split_at(svg_start).1.find('\n').unwrap();
let mut result = format!("<svg width=\"{}\"", self.width); let mut result = format!("<svg width=\"{}\"", self.width);
result.push_str(out.split_at(svg_start+split_at).1); result.push_str(out.split_at(svg_start + split_at).1);
result result
} }
@ -167,18 +164,14 @@ impl GraphRule {
); );
props.insert( props.insert(
"width".to_string(), "width".to_string(),
Property::new( Property::new(true, "SVG width".to_string(), Some("100%".to_string())),
true,
"SVG width".to_string(),
Some("100%".to_string()),
),
); );
Self { Self {
re: [Regex::new( re: [Regex::new(
r"\[graph\](?:\[((?:\\.|[^\[\]\\])*?)\])?(?:((?:\\.|[^\\\\])*?)\[/graph\])?", r"\[graph\](?:\[((?:\\.|[^\[\]\\])*?)\])?(?:((?:\\.|[^\\\\])*?)\[/graph\])?",
) )
.unwrap()], .unwrap()],
properties: PropertyParser{ properties: props }, properties: PropertyParser { properties: props },
} }
} }
} }
@ -191,7 +184,7 @@ impl RegexRule for GraphRule {
fn on_regex_match( fn on_regex_match(
&self, &self,
_: usize, _: usize,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -349,11 +342,11 @@ impl RegexRule for GraphRule {
); );
return reports; return reports;
} }
_ => panic!("Unknown error") _ => panic!("Unknown error"),
}, },
}; };
state.parser.push( state.push(
document, document,
Box::new(Graphviz { Box::new(Graphviz {
location: token, location: token,

View file

@ -1,6 +1,5 @@
use crate::document::document::Document; use crate::document::document::Document;
use crate::document::document::DocumentAccessors; use crate::document::document::DocumentAccessors;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -47,7 +46,7 @@ impl RegexRule for ImportRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
state: &mut ParserState, state: &ParserState,
document: &'a dyn Document<'a>, document: &'a dyn Document<'a>,
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -120,7 +119,8 @@ impl RegexRule for ImportRule {
// [Optional] import as // [Optional] import as
let import_as = match matches.get(1) { let import_as = match matches.get(1) {
Some(as_name) => match ImportRule::validate_as(state.parser.colors(), as_name.as_str()) { Some(as_name) => match ImportRule::validate_as(state.parser.colors(), as_name.as_str())
{
Ok(as_name) => as_name, Ok(as_name) => as_name,
Err(msg) => { Err(msg) => {
result.push( result.push(
@ -168,7 +168,7 @@ impl RegexRule for ImportRule {
// Close paragraph // Close paragraph
// TODO2: Check if this is safe to remove // TODO2: Check if this is safe to remove
if document.last_element::<Paragraph>().is_none() { if document.last_element::<Paragraph>().is_none() {
state.parser.push( state.push(
document, document,
Box::new(Paragraph { Box::new(Paragraph {
location: Token::new(token.end()..token.end(), token.source()), location: Token::new(token.end()..token.end(), token.source()),

View file

@ -6,7 +6,6 @@ use crate::document::element::Element;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::layout::LayoutHolder; use crate::parser::layout::LayoutHolder;
use crate::parser::layout::LayoutType; use crate::parser::layout::LayoutType;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -56,7 +55,7 @@ impl FromStr for LayoutToken {
mod default_layouts { mod default_layouts {
use crate::parser::layout::LayoutType; use crate::parser::layout::LayoutType;
use crate::parser::util::Property; use crate::parser::util::Property;
use crate::parser::util::PropertyParser; use crate::parser::util::PropertyParser;
use super::*; use super::*;
@ -249,7 +248,7 @@ impl RuleState for LayoutState {
fn on_remove<'a>( fn on_remove<'a>(
&self, &self,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>> {
let mut reports = vec![]; let mut reports = vec![];
@ -315,17 +314,17 @@ impl LayoutRule {
} }
} }
pub fn initialize_state(state: &mut ParserState) -> Rc<RefCell<dyn RuleState>> { pub fn initialize_state(state: &ParserState) -> Rc<RefCell<dyn RuleState>> {
let query = state.shared.rule_state.get(STATE_NAME); let mut rule_state_borrow = state.shared.rule_state.borrow_mut();
match query { match rule_state_borrow.get(STATE_NAME) {
Some(state) => state, Some(state) => state,
None => { None => {
// Insert as a new state // Insert as a new state
match state.shared.rule_state.insert( match rule_state_borrow.insert(
STATE_NAME.into(), STATE_NAME.into(),
Rc::new(LayoutState { stack: vec![] }), Rc::new(RefCell::new(LayoutState { stack: vec![] })),
) { ) {
Err(_) => panic!("Unknown error"), Err(err) => panic!("{err}"),
Ok(state) => state, Ok(state) => state,
} }
} }
@ -385,7 +384,7 @@ impl RegexRule for LayoutRule {
fn on_regex_match( fn on_regex_match(
&self, &self,
index: usize, index: usize,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -453,7 +452,7 @@ impl RegexRule for LayoutRule {
} }
// Get layout // Get layout
let layout_type = match state.shared.layouts.get(trimmed) { let layout_type = match state.shared.layouts.borrow().get(trimmed) {
None => { None => {
reports.push( reports.push(
Report::build(ReportKind::Error, token.source(), name.start()) Report::build(ReportKind::Error, token.source(), name.start())
@ -487,7 +486,7 @@ impl RegexRule for LayoutRule {
} }
}; };
state.parser.push( state.push(
document, document,
Box::new(Layout { Box::new(Layout {
location: token.clone(), location: token.clone(),
@ -498,11 +497,12 @@ impl RegexRule for LayoutRule {
}), }),
); );
state rule_state
.as_ref()
.borrow_mut() .borrow_mut()
.downcast_mut::<LayoutState>() .downcast_mut::<LayoutState>()
.map_or_else( .map_or_else(
|| panic!("Invalid state at: `{}`", STATE_NAME.as_str()), || panic!("Invalid state at: `{STATE_NAME}`"),
|s| s.stack.push((vec![token.clone()], layout_type.clone())), |s| s.stack.push((vec![token.clone()], layout_type.clone())),
); );
} }
@ -513,10 +513,10 @@ impl RegexRule for LayoutRule {
let (id, token_type, layout_type, properties) = if index == 1 let (id, token_type, layout_type, properties) = if index == 1
// LAYOUT_NEXT // LAYOUT_NEXT
{ {
let mut state_borrow = state.borrow_mut(); let mut rule_state_borrow = rule_state.as_ref().borrow_mut();
let state = state_borrow.downcast_mut::<LayoutState>().unwrap(); let layout_state = rule_state_borrow.downcast_mut::<LayoutState>().unwrap();
let (tokens, layout_type) = match state.stack.last_mut() { let (tokens, layout_type) = match layout_state.stack.last_mut() {
None => { None => {
reports.push( reports.push(
Report::build(ReportKind::Error, token.source(), token.start()) Report::build(ReportKind::Error, token.source(), token.start())
@ -576,10 +576,10 @@ impl RegexRule for LayoutRule {
) )
} else { } else {
// LAYOUT_END // LAYOUT_END
let mut state_borrow = state.borrow_mut(); let mut rule_state_borrow = rule_state.as_ref().borrow_mut();
let state = state_borrow.downcast_mut::<LayoutState>().unwrap(); let layout_state = rule_state_borrow.downcast_mut::<LayoutState>().unwrap();
let (tokens, layout_type) = match state.stack.last_mut() { let (tokens, layout_type) = match layout_state.stack.last_mut() {
None => { None => {
reports.push( reports.push(
Report::build(ReportKind::Error, token.source(), token.start()) Report::build(ReportKind::Error, token.source(), token.start())
@ -632,11 +632,11 @@ impl RegexRule for LayoutRule {
let layout_type = layout_type.clone(); let layout_type = layout_type.clone();
let id = tokens.len(); let id = tokens.len();
state.stack.pop(); layout_state.stack.pop();
(id, LayoutToken::End, layout_type, properties) (id, LayoutToken::End, layout_type, properties)
}; };
state.parser.push( state.push(
document, document,
Box::new(Layout { Box::new(Layout {
location: token, location: token,
@ -676,11 +676,12 @@ impl RegexRule for LayoutRule {
CTX.with_borrow(|ctx| { CTX.with_borrow(|ctx| {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
// Make sure the state has been initialized // Make sure the rule state has been initialized
let state = LayoutRule::initialize_state(ctx.parser); let rule_state = LayoutRule::initialize_state(ctx.state);
// Get layout // Get layout
let layout_type = match ctx.parser.get_layout(layout.as_str()) //
let layout_type = match ctx.state.shared.layouts.borrow().get(layout.as_str())
{ {
None => { None => {
result = Err(BadArgument { result = Err(BadArgument {
@ -712,7 +713,7 @@ impl RegexRule for LayoutRule {
let id = match layout_token { let id = match layout_token {
LayoutToken::Begin => { LayoutToken::Begin => {
ctx.parser.push( ctx.state.push(
ctx.document, ctx.document,
Box::new(Layout { Box::new(Layout {
location: ctx.location.clone(), location: ctx.location.clone(),
@ -723,20 +724,21 @@ impl RegexRule for LayoutRule {
}), }),
); );
state rule_state
.as_ref()
.borrow_mut() .borrow_mut()
.downcast_mut::<LayoutState>() .downcast_mut::<LayoutState>()
.map_or_else( .map_or_else(
|| panic!("Invalid state at: `{}`", STATE_NAME.as_str()), || panic!("Invalid state at: `{STATE_NAME}`"),
|s| s.stack.push((vec![ctx.location.clone()], layout_type.clone())), |s| s.stack.push((vec![ctx.location.clone()], layout_type.clone())),
); );
return; return;
}, },
LayoutToken::Next => { LayoutToken::Next => {
let mut state_borrow = state.borrow_mut(); let mut state_borrow = rule_state.as_ref().borrow_mut();
let state = state_borrow.downcast_mut::<LayoutState>().unwrap(); let layout_state = state_borrow.downcast_mut::<LayoutState>().unwrap();
let (tokens, current_layout_type) = match state.stack.last_mut() { let (tokens, current_layout_type) = match layout_state.stack.last_mut() {
None => { None => {
result = Err(BadArgument { result = Err(BadArgument {
to: Some("push".to_string()), to: Some("push".to_string()),
@ -781,10 +783,10 @@ impl RegexRule for LayoutRule {
tokens.len() - 1 tokens.len() - 1
}, },
LayoutToken::End => { LayoutToken::End => {
let mut state_borrow = state.borrow_mut(); let mut state_borrow = rule_state.as_ref().borrow_mut();
let state = state_borrow.downcast_mut::<LayoutState>().unwrap(); let layout_state = state_borrow.downcast_mut::<LayoutState>().unwrap();
let (tokens, current_layout_type) = match state.stack.last_mut() { let (tokens, current_layout_type) = match layout_state.stack.last_mut() {
None => { None => {
result = Err(BadArgument { result = Err(BadArgument {
to: Some("push".to_string()), to: Some("push".to_string()),
@ -826,12 +828,12 @@ impl RegexRule for LayoutRule {
} }
let id = tokens.len(); let id = tokens.len();
state.stack.pop(); layout_state.stack.pop();
id id
} }
}; };
ctx.state.parser.push( ctx.state.push(
ctx.document, ctx.document,
Box::new(Layout { Box::new(Layout {
location: ctx.location.clone(), location: ctx.location.clone(),
@ -854,7 +856,7 @@ impl RegexRule for LayoutRule {
} }
fn register_layouts(&self, holder: &mut LayoutHolder) { fn register_layouts(&self, holder: &mut LayoutHolder) {
holder.insert(Rc::new(default_layouts::Centered::default())); holder.insert(Rc::new(default_layouts::Centered::default()));
holder.insert(Rc::new(default_layouts::Split::default())); holder.insert(Rc::new(default_layouts::Split::default()));
} }
} }
@ -864,6 +866,7 @@ mod tests {
use crate::elements::paragraph::Paragraph; use crate::elements::paragraph::Paragraph;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;

View file

@ -5,7 +5,6 @@ use crate::document::element::ContainerElement;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -92,7 +91,7 @@ impl RegexRule for LinkRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
state: &mut ParserState, state: &ParserState,
document: &'a (dyn Document<'a> + 'a), document: &'a (dyn Document<'a> + 'a),
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -197,7 +196,7 @@ impl RegexRule for LinkRule {
_ => panic!("Empty link url"), _ => panic!("Empty link url"),
}; };
state.parser.push( state.push(
document, document,
Box::new(Link { Box::new(Link {
location: token, location: token,
@ -224,7 +223,7 @@ impl RegexRule for LinkRule {
display, display,
)); ));
let display_content = let display_content =
match util::parse_paragraph(ctx.parser, source, ctx.document) { match util::parse_paragraph(ctx.state, source, ctx.document) {
Err(err) => { Err(err) => {
result = Err(BadArgument { result = Err(BadArgument {
to: Some("push".to_string()), to: Some("push".to_string()),
@ -241,7 +240,7 @@ impl RegexRule for LinkRule {
} }
}; };
ctx.parser.push( ctx.state.push(
ctx.document, ctx.document,
Box::new(Link { Box::new(Link {
location: ctx.location.clone(), location: ctx.location.clone(),
@ -267,6 +266,7 @@ mod tests {
use crate::elements::style::Style; use crate::elements::style::Style;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;
@ -284,7 +284,7 @@ Some [link](url).
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let doc = parser.parse(source, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {
@ -314,7 +314,7 @@ nml.link.push("**BOLD link**", "another url")
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let doc = parser.parse(source, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {

View file

@ -150,7 +150,7 @@ impl ListRule {
// Close // Close
for i in start_pos..current.len() { for i in start_pos..current.len() {
state.parser.push( state.push(
document, document,
Box::new(ListMarker { Box::new(ListMarker {
location: token.clone(), location: token.clone(),
@ -162,7 +162,7 @@ impl ListRule {
// Open // Open
for i in start_pos..target.len() { for i in start_pos..target.len() {
state.parser.push( state.push(
document, document,
Box::new(ListMarker { Box::new(ListMarker {
location: token.clone(), location: token.clone(),
@ -260,7 +260,7 @@ impl Rule for ListRule {
fn on_match<'a>( fn on_match<'a>(
&self, &self,
state: &mut ParserState, state: &ParserState,
document: &'a dyn Document<'a>, document: &'a dyn Document<'a>,
cursor: Cursor, cursor: Cursor,
_match_data: Box<dyn Any>, _match_data: Box<dyn Any>,
@ -403,7 +403,7 @@ impl Rule for ListRule {
ListRule::push_markers(&token, state, document, &vec![], &depth); ListRule::push_markers(&token, state, document, &vec![], &depth);
} }
state.parser.push( state.push(
document, document,
Box::new(ListEntry { Box::new(ListEntry {
location: Token::new( location: Token::new(

View file

@ -7,8 +7,6 @@ use ariadne::Fmt;
use ariadne::Label; use ariadne::Label;
use ariadne::Report; use ariadne::Report;
use ariadne::ReportKind; use ariadne::ReportKind;
use mlua::Function;
use mlua::Lua;
use regex::Captures; use regex::Captures;
use regex::Match; use regex::Match;
use regex::Regex; use regex::Regex;
@ -23,7 +21,6 @@ use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::document::element::ReferenceableElement; use crate::document::element::ReferenceableElement;
use crate::document::references::validate_refname; use crate::document::references::validate_refname;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -255,7 +252,7 @@ impl MediaRule {
.multi_line(true) .multi_line(true)
.build() .build()
.unwrap()], .unwrap()],
properties: PropertyParser{ properties: props }, properties: PropertyParser { properties: props },
} }
} }
@ -334,7 +331,7 @@ impl RegexRule for MediaRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
state: &mut ParserState, state: &ParserState,
document: &'a (dyn Document<'a> + 'a), document: &'a (dyn Document<'a> + 'a),
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -378,7 +375,8 @@ impl RegexRule for MediaRule {
}; };
// Properties // Properties
let properties = match self.parse_properties(state.parser.colors(), &token, &matches.get(3)) { let properties = match self.parse_properties(state.parser.colors(), &token, &matches.get(3))
{
Ok(pm) => pm, Ok(pm) => pm,
Err(report) => { Err(report) => {
reports.push(report); reports.push(report);
@ -481,7 +479,7 @@ impl RegexRule for MediaRule {
let mut group = match document.last_element_mut::<Media>() { let mut group = match document.last_element_mut::<Media>() {
Some(group) => group, Some(group) => group,
None => { None => {
state.parser.push( state.push(
document, document,
Box::new(Media { Box::new(Media {
location: token.clone(), location: token.clone(),
@ -521,6 +519,7 @@ impl RegexRule for MediaRule {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use super::*; use super::*;

View file

@ -11,7 +11,6 @@ use crate::document::document::Document;
use crate::document::element::ContainerElement; use crate::document::element::ContainerElement;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::Rule; use crate::parser::rule::Rule;
use crate::parser::source::Cursor; use crate::parser::source::Cursor;
@ -115,17 +114,17 @@ impl Rule for ParagraphRule {
fn on_match( fn on_match(
&self, &self,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
cursor: Cursor, cursor: Cursor,
_match_data: Option<Box<dyn Any>>, _match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) { ) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
let end_cursor = match self.re.captures_at(cursor.source.content(), cursor.pos) { let end_cursor = match self.re.captures_at(cursor.source.content(), cursor.pos) {
None => panic!("Unknown error"), None => panic!("Unknown error"),
Some(capture) => cursor.at(capture.get(0).unwrap().end() - 1), Some(capture) => cursor.at(capture.get(0).unwrap().end() - 1),
}; };
state.parser.push( state.push(
document, document,
Box::new(Paragraph { Box::new(Paragraph {
location: Token::new(cursor.pos..end_cursor.pos, cursor.source.clone()), location: Token::new(cursor.pos..end_cursor.pos, cursor.source.clone()),
@ -142,6 +141,7 @@ mod tests {
use crate::elements::paragraph::Paragraph; use crate::elements::paragraph::Paragraph;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;

View file

@ -3,7 +3,6 @@ use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -79,7 +78,7 @@ impl RegexRule for RawRule {
fn on_regex_match( fn on_regex_match(
&self, &self,
_index: usize, _index: usize,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -208,7 +207,7 @@ impl RegexRule for RawRule {
}, },
}; };
state.parser.push( state.push(
document, document,
Box::new(Raw { Box::new(Raw {
location: token.clone(), location: token.clone(),
@ -243,7 +242,7 @@ impl RegexRule for RawRule {
CTX.with_borrow(|ctx| { CTX.with_borrow(|ctx| {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
ctx.state.parser.push( ctx.state.push(
ctx.document, ctx.document,
Box::new(Raw { Box::new(Raw {
location: ctx.location.clone(), location: ctx.location.clone(),
@ -269,7 +268,8 @@ mod tests {
use crate::elements::paragraph::Paragraph; use crate::elements::paragraph::Paragraph;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::source::SourceFile; use crate::parser::parser::Parser;
use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;
#[test] #[test]

View file

@ -6,8 +6,6 @@ use ariadne::Fmt;
use ariadne::Label; use ariadne::Label;
use ariadne::Report; use ariadne::Report;
use ariadne::ReportKind; use ariadne::ReportKind;
use mlua::Function;
use mlua::Lua;
use regex::Captures; use regex::Captures;
use regex::Match; use regex::Match;
use regex::Regex; use regex::Regex;
@ -18,7 +16,6 @@ use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::document::references::validate_refname; use crate::document::references::validate_refname;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -83,7 +80,7 @@ impl ReferenceRule {
); );
Self { Self {
re: [Regex::new(r"§\{(.*?)\}(\[((?:\\.|[^\\\\])*?)\])?").unwrap()], re: [Regex::new(r"§\{(.*?)\}(\[((?:\\.|[^\\\\])*?)\])?").unwrap()],
properties: PropertyParser{ properties: props }, properties: PropertyParser { properties: props },
} }
} }
@ -136,7 +133,7 @@ impl RegexRule for ReferenceRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
state: &mut ParserState, state: &ParserState,
document: &'a (dyn Document<'a> + 'a), document: &'a (dyn Document<'a> + 'a),
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -179,7 +176,8 @@ impl RegexRule for ReferenceRule {
} }
}; };
// Properties // Properties
let properties = match self.parse_properties(state.parser.colors(), &token, &matches.get(3)) { let properties = match self.parse_properties(state.parser.colors(), &token, &matches.get(3))
{
Ok(pm) => pm, Ok(pm) => pm,
Err(report) => { Err(report) => {
reports.push(report); reports.push(report);
@ -194,7 +192,7 @@ impl RegexRule for ReferenceRule {
.ok() .ok()
.and_then(|(_, s)| Some(s)); .and_then(|(_, s)| Some(s));
state.parser.push( state.push(
document, document,
Box::new(Reference { Box::new(Reference {
location: token, location: token,

View file

@ -1,7 +1,6 @@
use crate::document::document::Document; use crate::document::document::Document;
use crate::lua::kernel::Kernel; use crate::lua::kernel::Kernel;
use crate::lua::kernel::KernelContext; use crate::lua::kernel::KernelContext;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -13,7 +12,6 @@ use ariadne::Fmt;
use ariadne::Label; use ariadne::Label;
use ariadne::Report; use ariadne::Report;
use ariadne::ReportKind; use ariadne::ReportKind;
use mlua::Function;
use mlua::Lua; use mlua::Lua;
use regex::Captures; use regex::Captures;
use regex::Regex; use regex::Regex;
@ -85,7 +83,7 @@ impl RegexRule for ScriptRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
index: usize, index: usize,
state: &mut ParserState, state: &ParserState,
document: &'a dyn Document<'a>, document: &'a dyn Document<'a>,
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -94,29 +92,33 @@ impl RegexRule for ScriptRule {
let kernel_name = match matches.get(1) { let kernel_name = match matches.get(1) {
None => "main".to_string(), None => "main".to_string(),
Some(name) => match ScriptRule::validate_kernel_name(state.parser.colors(), name.as_str()) { Some(name) => {
Ok(name) => name, match ScriptRule::validate_kernel_name(state.parser.colors(), name.as_str()) {
Err(e) => { Ok(name) => name,
reports.push( Err(e) => {
Report::build(ReportKind::Error, token.source(), name.start()) reports.push(
.with_message("Invalid kernel name") Report::build(ReportKind::Error, token.source(), name.start())
.with_label( .with_message("Invalid kernel name")
Label::new((token.source(), name.range())) .with_label(
.with_message(e) Label::new((token.source(), name.range()))
.with_color(state.parser.colors().error), .with_message(e)
) .with_color(state.parser.colors().error),
.finish(), )
); .finish(),
return reports; );
return reports;
}
} }
}, }
};
let mut kernels_borrow = state.shared.kernels.borrow_mut();
let kernel = match kernels_borrow.get(kernel_name.as_str()) {
Some(kernel) => kernel,
None => {
kernels_borrow.insert(kernel_name.clone(), Kernel::new(state.parser));
kernels_borrow.get(kernel_name.as_str()).unwrap()
}
}; };
let kernel = state.shared.kernels
.get(kernel_name.as_str())
.unwrap_or_else(|| {
state.shared.kernels.insert(kernel_name.to_string(), Kernel::new(state));
state.shared.kernels.get(kernel_name.as_str()).unwrap()
});
let kernel_data = matches let kernel_data = matches
.get(if index == 0 { 2 } else { 3 }) .get(if index == 0 { 2 } else { 3 })
@ -227,7 +229,7 @@ impl RegexRule for ScriptRule {
// Eval to text // Eval to text
{ {
if !result.is_empty() { if !result.is_empty() {
state.parser.push( state.push(
document, document,
Box::new(Text::new( Box::new(Text::new(
Token::new(1..source.content().len(), source.clone()), Token::new(1..source.content().len(), source.clone()),
@ -245,7 +247,9 @@ impl RegexRule for ScriptRule {
)) as Rc<dyn Source>; )) as Rc<dyn Source>;
state.with_state(|new_state| { state.with_state(|new_state| {
new_state.parser.parse_into(new_state, parse_source, document); new_state
.parser
.parse_into(new_state, parse_source, document);
}) })
} }
} }
@ -273,7 +277,7 @@ impl RegexRule for ScriptRule {
let ctx = KernelContext { let ctx = KernelContext {
location: Token::new(0..source.content().len(), source.clone()), location: Token::new(0..source.content().len(), source.clone()),
parser_state: state, state,
document, document,
}; };
@ -290,6 +294,7 @@ mod tests {
use crate::elements::paragraph::Paragraph; use crate::elements::paragraph::Paragraph;
use crate::elements::style::Style; use crate::elements::style::Style;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;
@ -315,7 +320,7 @@ Evaluation: %<! make_ref("hello", "id")>%
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let doc = parser.parse(source, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph; Paragraph;

View file

@ -5,7 +5,6 @@ use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::document::element::ReferenceableElement; use crate::document::element::ReferenceableElement;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -162,7 +161,7 @@ impl RegexRule for SectionRule {
fn on_regex_match( fn on_regex_match(
&self, &self,
_: usize, _: usize,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
token: Token, token: Token,
matches: regex::Captures, matches: regex::Captures,
@ -294,12 +293,15 @@ impl RegexRule for SectionRule {
}; };
// Get style // Get style
let style = state.shared.styles let style = state
.current_style(section_style::STYLE_KEY) .shared
.styles
.borrow()
.current(section_style::STYLE_KEY)
.downcast_rc::<SectionStyle>() .downcast_rc::<SectionStyle>()
.unwrap(); .unwrap();
state.parser.push( state.push(
document, document,
Box::new(Section { Box::new(Section {
location: token.clone(), location: token.clone(),
@ -342,12 +344,15 @@ impl RegexRule for SectionRule {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
// Get style // Get style
let style = ctx let style = ctx
.parser .state
.current_style(section_style::STYLE_KEY) .shared
.styles
.borrow()
.current(section_style::STYLE_KEY)
.downcast_rc::<SectionStyle>() .downcast_rc::<SectionStyle>()
.unwrap(); .unwrap();
ctx.parser.push( ctx.state.push(
ctx.document, ctx.document,
Box::new(Section { Box::new(Section {
location: ctx.location.clone(), location: ctx.location.clone(),
@ -371,7 +376,7 @@ impl RegexRule for SectionRule {
} }
fn register_styles(&self, holder: &mut StyleHolder) { fn register_styles(&self, holder: &mut StyleHolder) {
holder.set_current_style(Rc::new(SectionStyle::default())); holder.set_current(Rc::new(SectionStyle::default()));
} }
} }
@ -411,6 +416,7 @@ mod section_style {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;
@ -491,6 +497,8 @@ nml.section.push("6", 6, "", "refname")
let state = ParserState::new(&parser, None); let state = ParserState::new(&parser, None);
let _ = parser.parse(state, source, None); let _ = parser.parse(state, source, None);
// TODO2
/*
let style = state.shared let style = state.shared
.styles .styles
.current_style(section_style::STYLE_KEY) .current_style(section_style::STYLE_KEY)
@ -499,5 +507,6 @@ nml.section.push("6", 6, "", "refname")
assert_eq!(style.link_pos, SectionLinkPos::None); assert_eq!(style.link_pos, SectionLinkPos::None);
assert_eq!(style.link, ["a".to_string(), "b".to_string(), "c".to_string()]); assert_eq!(style.link, ["a".to_string(), "b".to_string(), "c".to_string()]);
*/
} }
} }

View file

@ -4,7 +4,6 @@ use crate::document::document::Document;
use crate::document::document::DocumentAccessors; use crate::document::document::DocumentAccessors;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -80,7 +79,7 @@ impl RuleState for StyleState {
fn on_remove<'a>( fn on_remove<'a>(
&self, &self,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>> {
let mut reports = vec![]; let mut reports = vec![];
@ -154,7 +153,7 @@ impl StyleRule {
} }
} }
static STATE_NAME : &'static str = "elements.style"; static STATE_NAME: &'static str = "elements.style";
impl RegexRule for StyleRule { impl RegexRule for StyleRule {
fn name(&self) -> &'static str { "Style" } fn name(&self) -> &'static str { "Style" }
@ -164,17 +163,20 @@ impl RegexRule for StyleRule {
fn on_regex_match( fn on_regex_match(
&self, &self,
index: usize, index: usize,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
token: Token, token: Token,
_matches: Captures, _matches: Captures,
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>> {
let query = state.shared.rule_state.get(&STATE_NAME); let query = state.shared.rule_state.borrow().get(STATE_NAME);
let state = match query { let style_state = match query {
Some(state) => state, Some(state) => state,
None => { None => {
// Insert as a new state // Insert as a new state
match state.shared.rule_state match state
.shared
.rule_state
.borrow_mut()
.insert(STATE_NAME.into(), Rc::new(RefCell::new(StyleState::new()))) .insert(STATE_NAME.into(), Rc::new(RefCell::new(StyleState::new())))
{ {
Err(_) => panic!("Unknown error"), Err(_) => panic!("Unknown error"),
@ -183,11 +185,11 @@ impl RegexRule for StyleRule {
} }
}; };
if let Some(style_state) = state.borrow_mut().downcast_mut::<StyleState>() { if let Some(style_state) = style_state.borrow_mut().downcast_mut::<StyleState>() {
style_state.toggled[index] = style_state.toggled[index] style_state.toggled[index] = style_state.toggled[index]
.clone() .clone()
.map_or(Some(token.clone()), |_| None); .map_or(Some(token.clone()), |_| None);
state.parser.push( state.push(
document, document,
Box::new(Style::new( Box::new(Style::new(
token.clone(), token.clone(),
@ -196,7 +198,7 @@ impl RegexRule for StyleRule {
)), )),
); );
} else { } else {
panic!("Invalid state at `{}`", STATE_NAME.as_str()); panic!("Invalid state at `{STATE_NAME}`");
} }
return vec![]; return vec![];
@ -207,6 +209,7 @@ impl RegexRule for StyleRule {
mod tests { mod tests {
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;
@ -227,7 +230,7 @@ __`UNDERLINE+EM`__
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let doc = parser.parse(source, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {

View file

@ -14,8 +14,6 @@ use ariadne::Report;
use ariadne::ReportKind; use ariadne::ReportKind;
use crypto::digest::Digest; use crypto::digest::Digest;
use crypto::sha2::Sha512; use crypto::sha2::Sha512;
use mlua::Function;
use mlua::Lua;
use regex::Captures; use regex::Captures;
use regex::Match; use regex::Match;
use regex::Regex; use regex::Regex;
@ -27,7 +25,6 @@ use crate::compiler::compiler::Target;
use crate::document::document::Document; use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -305,7 +302,7 @@ impl RegexRule for TexRule {
fn on_regex_match( fn on_regex_match(
&self, &self,
index: usize, index: usize,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
token: Token, token: Token,
matches: Captures, matches: Captures,
@ -355,7 +352,8 @@ impl RegexRule for TexRule {
}; };
// Properties // Properties
let properties = match self.parse_properties(state.parser.colors(), &token, &matches.get(1)) { let properties = match self.parse_properties(state.parser.colors(), &token, &matches.get(1))
{
Ok(pm) => pm, Ok(pm) => pm,
Err(report) => { Err(report) => {
reports.push(report); reports.push(report);
@ -413,7 +411,7 @@ impl RegexRule for TexRule {
.and_then(|(_, value)| Some(value)) .and_then(|(_, value)| Some(value))
.unwrap(); .unwrap();
state.parser.push( state.push(
document, document,
Box::new(Tex { Box::new(Tex {
mathmode: index == 1, mathmode: index == 1,
@ -433,6 +431,7 @@ impl RegexRule for TexRule {
mod tests { mod tests {
use crate::elements::paragraph::Paragraph; use crate::elements::paragraph::Paragraph;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;
@ -451,7 +450,7 @@ $[kind=block,env=another] e^{i\pi}=-1$
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let doc = parser.parse(source, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) }; Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) };
@ -473,7 +472,7 @@ $[env=another] e^{i\pi}=-1$
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let doc = parser.parse(source, None); let doc = parser.parse(ParserState::new(&parser, None), source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {

View file

@ -11,7 +11,6 @@ use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::Rule; use crate::parser::rule::Rule;
use crate::parser::source::Cursor; use crate::parser::source::Cursor;
@ -53,10 +52,10 @@ impl Rule for TextRule {
fn on_match( fn on_match(
&self, &self,
_state: &mut ParserState, _state: &ParserState,
_document: &dyn Document, _document: &dyn Document,
_cursor: Cursor, _cursor: Cursor,
_match_data: Option<Box<dyn Any>>, _match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) { ) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>) {
panic!("Text cannot match"); panic!("Text cannot match");
} }
@ -68,7 +67,7 @@ impl Rule for TextRule {
lua.create_function(|_, content: String| { lua.create_function(|_, content: String| {
CTX.with_borrow(|ctx| { CTX.with_borrow(|ctx| {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
ctx.state.parser.push( ctx.state.push(
ctx.document, ctx.document,
Box::new(Text { Box::new(Text {
location: ctx.location.clone(), location: ctx.location.clone(),

View file

@ -3,7 +3,6 @@ use crate::document::variable::BaseVariable;
use crate::document::variable::PathVariable; use crate::document::variable::PathVariable;
use crate::document::variable::Variable; use crate::document::variable::Variable;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -124,7 +123,7 @@ impl RegexRule for VariableRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
state: &mut ParserState, state: &ParserState,
document: &'a dyn Document, document: &'a dyn Document,
token: Token, token: Token,
matches: regex::Captures, matches: regex::Captures,
@ -316,7 +315,7 @@ impl RegexRule for VariableSubstitutionRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_index: usize, _index: usize,
state: &mut ParserState, state: &ParserState,
document: &'a dyn Document<'a>, document: &'a dyn Document<'a>,
token: Token, token: Token,
matches: regex::Captures, matches: regex::Captures,
@ -417,7 +416,7 @@ impl RegexRule for VariableSubstitutionRule {
_ => panic!("Unknown error"), _ => panic!("Unknown error"),
}; };
variable.parse(token, state, document); variable.parse(state, token, document);
return result; return result;
} }

View file

@ -1,11 +1,6 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::cell::RefMut;
use std::collections::HashMap; use std::collections::HashMap;
use mlua::Error;
use mlua::FromLuaMulti;
use mlua::Function;
use mlua::IntoLuaMulti;
use mlua::Lua; use mlua::Lua;
use crate::document::document::Document; use crate::document::document::Document;
@ -17,7 +12,6 @@ pub struct KernelContext<'a, 'b, 'c> {
pub location: Token, pub location: Token,
pub state: &'a ParserState<'a, 'b>, pub state: &'a ParserState<'a, 'b>,
pub document: &'c dyn Document<'c>, pub document: &'c dyn Document<'c>,
//pub parser: &'a dyn Parser,
} }
thread_local! { thread_local! {
@ -40,7 +34,7 @@ impl Kernel {
let table = lua.create_table().unwrap(); let table = lua.create_table().unwrap();
// TODO: Export this so we can check for duplicate rules based on this name // TODO: Export this so we can check for duplicate rules based on this name
let name = rule.name().to_lowercase().replace(' ', "_"); let name = rule.name().to_lowercase().replace(' ', "_");
for (fun_name, fun) in rule.lua_bindings(&lua) { for (fun_name, fun) in rule.register_bindings(&lua) {
table.set(fun_name, fun).unwrap(); table.set(fun_name, fun).unwrap();
} }
nml_table.set(name, table).unwrap(); nml_table.set(name, table).unwrap();
@ -73,11 +67,9 @@ pub struct KernelHolder {
} }
impl KernelHolder { impl KernelHolder {
pub fn get(&self, kernel_name: &str) -> Option<&Kernel> { pub fn get(&self, kernel_name: &str) -> Option<&Kernel> { self.kernels.get(kernel_name) }
self.kernels.get(kernel_name)
}
pub fn insert(&self, kernel_name: String, kernel: Kernel) { pub fn insert(&mut self, kernel_name: String, kernel: Kernel) {
self.kernels.insert(kernel_name, kernel) self.kernels.insert(kernel_name, kernel);
} }
} }

View file

@ -47,13 +47,16 @@ NML version: 0.4\n"
); );
} }
fn parse(parser: &LangParser, input: &str, debug_opts: &Vec<String>) -> Result<Box<dyn Document<'static>>, String> { fn parse(
parser: &LangParser,
input: &str,
debug_opts: &Vec<String>,
) -> Result<Box<dyn Document<'static>>, String> {
println!("Parsing {input}..."); println!("Parsing {input}...");
let parser = LangParser::default();
// Parse // Parse
let source = SourceFile::new(input.to_string(), None).unwrap(); let source = SourceFile::new(input.to_string(), None).unwrap();
let doc = parser.parse(ParserState::new(&parser, None), Rc::new(source), None); let doc = parser.parse(ParserState::new(parser, None), Rc::new(source), None);
if debug_opts.contains(&"ast".to_string()) { if debug_opts.contains(&"ast".to_string()) {
println!("-- BEGIN AST DEBUGGING --"); println!("-- BEGIN AST DEBUGGING --");
@ -218,8 +221,7 @@ fn main() -> ExitCode {
} }
match std::fs::metadata(&output) { match std::fs::metadata(&output) {
Ok(output_meta) => { Ok(output_meta) => {
if !output_meta.is_dir() if !output_meta.is_dir() {
{
eprintln!("Input is a directory, but ouput is not a directory, halting"); eprintln!("Input is a directory, but ouput is not a directory, halting");
return ExitCode::FAILURE; return ExitCode::FAILURE;
} }

View file

@ -1,6 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use std::ops::Deref;
use ariadne::Report; use ariadne::Report;
@ -25,13 +26,13 @@ pub trait CustomStyle: core::fmt::Debug {
fn on_start<'a>( fn on_start<'a>(
&self, &self,
location: Token, location: Token,
state: &mut ParserState, state: &ParserState,
document: &'a (dyn Document<'a> + 'a), document: &'a (dyn Document<'a> + 'a),
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>>; ) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>>;
fn on_end<'a>( fn on_end<'a>(
&self, &self,
location: Token, location: Token,
state: &mut ParserState, state: &ParserState,
document: &'a (dyn Document<'a> + 'a), document: &'a (dyn Document<'a> + 'a),
) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>>; ) -> Vec<Report<(Rc<dyn Source>, Range<usize>)>>;
} }
@ -42,13 +43,21 @@ pub struct CustomStyleHolder {
} }
impl CustomStyleHolder { impl CustomStyleHolder {
fn get(&self, style_name: &str) -> Option<Rc<dyn CustomStyle>> { pub fn get(&self, style_name: &str) -> Option<Rc<dyn CustomStyle>> {
self.custom_styles self.custom_styles
.get(style_name) .get(style_name)
.map(|style| style.clone()) .map(|style| style.clone())
} }
fn insert(&mut self, style: Rc<dyn CustomStyle>) { pub fn insert(&mut self, style: Rc<dyn CustomStyle>) {
self.custom_styles.insert(style.name().into(), style); self.custom_styles.insert(style.name().into(), style);
} }
} }
impl Deref for CustomStyleHolder {
type Target = HashMap<String, Rc<dyn CustomStyle>>;
fn deref(&self) -> &Self::Target {
&self.custom_styles
}
}

View file

@ -1,23 +1,11 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashSet;
use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use ariadne::Label;
use ariadne::Report;
use crate::document::document::Document; use crate::document::document::Document;
use crate::document::document::DocumentAccessors;
use crate::document::element::ContainerElement;
use crate::document::element::DocumentEnd; use crate::document::element::DocumentEnd;
use crate::document::element::ElemKind;
use crate::document::element::Element;
use crate::document::langdocument::LangDocument; use crate::document::langdocument::LangDocument;
use crate::elements::paragraph::Paragraph;
use crate::elements::registrar::register; use crate::elements::registrar::register;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::source::SourceFile;
use crate::parser::source::VirtualSource;
use super::parser::Parser; use super::parser::Parser;
use super::parser::ParserState; use super::parser::ParserState;
@ -44,17 +32,11 @@ impl LangParser {
rules: vec![], rules: vec![],
colors: ReportColors::with_colors(), colors: ReportColors::with_colors(),
err_flag: RefCell::new(false), err_flag: RefCell::new(false),
//matches: RefCell::new(Vec::new()),
//state: RefCell::new(StateHolder::new()),
//kernels: RefCell::new(HashMap::new()),
//styles: RefCell::new(HashMap::new()),
//layouts: RefCell::new(HashMap::new()),
//custom_styles: RefCell::new(HashMap::new()),
}; };
// Register rules
// TODO2: use https://docs.rs/inventory/latest/inventory/
register(&mut s);
// Register rules
// TODO: use https://docs.rs/inventory/latest/inventory/
register(&mut s);
s s
} }
@ -64,6 +46,7 @@ impl Parser for LangParser {
fn colors(&self) -> &ReportColors { &self.colors } fn colors(&self) -> &ReportColors { &self.colors }
fn rules(&self) -> &Vec<Box<dyn Rule>> { &self.rules } fn rules(&self) -> &Vec<Box<dyn Rule>> { &self.rules }
fn rules_mut(&mut self) -> &mut Vec<Box<dyn Rule>> { &mut self.rules }
fn has_error(&self) -> bool { *self.err_flag.borrow() } fn has_error(&self) -> bool { *self.err_flag.borrow() }
@ -81,11 +64,11 @@ impl Parser for LangParser {
if let Some(parent) = parent if let Some(parent) = parent
// Terminate parent's paragraph state // Terminate parent's paragraph state
{ {
Parser::handle_reports(&self, self.handle_reports(state.shared.rule_state.borrow_mut().on_scope_end(
parent.source(), &state,
state.shared.rule_state parent,
.on_scope_end(self, parent, super::state::Scope::PARAGRAPH), super::state::Scope::PARAGRAPH,
); ));
} }
loop { loop {
@ -95,7 +78,7 @@ impl Parser for LangParser {
let text_content = let text_content =
util::process_text(&doc, &content.as_str()[cursor.pos..rule_pos.pos]); util::process_text(&doc, &content.as_str()[cursor.pos..rule_pos.pos]);
if !text_content.is_empty() { if !text_content.is_empty() {
self.push( state.push(
&doc, &doc,
Box::new(Text::new( Box::new(Text::new(
Token::new(cursor.pos..rule_pos.pos, source.clone()), Token::new(cursor.pos..rule_pos.pos, source.clone()),
@ -107,9 +90,10 @@ impl Parser for LangParser {
if let Some((rule_index, match_data)) = result.take() { if let Some((rule_index, match_data)) = result.take() {
// Rule callback // Rule callback
let dd: &'a dyn Document = unsafe { std::mem::transmute(&doc as &dyn Document) }; let dd: &'a dyn Document = unsafe { std::mem::transmute(&doc as &dyn Document) };
let (new_cursor, reports) = self.rules[rule_index].on_match(self, dd, rule_pos, match_data); let (new_cursor, reports) =
self.rules[rule_index].on_match(&state, dd, rule_pos, match_data);
self.handle_reports(doc.source(), reports); self.handle_reports(reports);
// Advance // Advance
cursor = new_cursor; cursor = new_cursor;
@ -120,14 +104,15 @@ impl Parser for LangParser {
} }
} }
// State // Rule States
self.handle_reports(
doc.source(),
state.shared.rule_state
.on_scope_end(&mut state, &doc, super::state::Scope::DOCUMENT),
);
self.push( self.handle_reports(state.shared.rule_state.borrow_mut().on_scope_end(
&state,
&doc,
super::state::Scope::DOCUMENT,
));
state.push(
&doc, &doc,
Box::new(DocumentEnd(Token::new( Box::new(DocumentEnd(Token::new(
doc.source().content().len()..doc.source().content().len(), doc.source().content().len()..doc.source().content().len(),
@ -138,7 +123,12 @@ impl Parser for LangParser {
return Box::new(doc); return Box::new(doc);
} }
fn parse_into<'a>(&self, state: mut ParserState, source: Rc<dyn Source>, document: &'a dyn Document<'a>) { fn parse_into<'a>(
&self,
state: ParserState,
source: Rc<dyn Source>,
document: &'a dyn Document<'a>,
) {
let content = source.content(); let content = source.content();
let mut cursor = Cursor::new(0usize, source.clone()); let mut cursor = Cursor::new(0usize, source.clone());
@ -149,7 +139,7 @@ impl Parser for LangParser {
let text_content = let text_content =
util::process_text(document, &content.as_str()[cursor.pos..rule_pos.pos]); util::process_text(document, &content.as_str()[cursor.pos..rule_pos.pos]);
if !text_content.is_empty() { if !text_content.is_empty() {
self.push( state.push(
document, document,
Box::new(Text::new( Box::new(Text::new(
Token::new(cursor.pos..rule_pos.pos, source.clone()), Token::new(cursor.pos..rule_pos.pos, source.clone()),
@ -160,9 +150,10 @@ impl Parser for LangParser {
if let Some((rule_index, match_data)) = result.take() { if let Some((rule_index, match_data)) = result.take() {
// Rule callback // Rule callback
let (new_cursor, reports) = self.rules[rule_index].on_match(&mut state, document, rule_pos, match_data); let (new_cursor, reports) =
self.rules[rule_index].on_match(&state, document, rule_pos, match_data);
self.handle_reports(document.source(), reports); self.handle_reports(reports);
// Advance // Advance
cursor = new_cursor; cursor = new_cursor;

View file

@ -1,6 +1,4 @@
use std::any::Any; use std::any::Any;
use std::cell::Ref;
use std::cell::RefMut;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
@ -41,7 +39,7 @@ impl LayoutHolder {
self.layouts.get(layout_name).map(|layout| layout.clone()) self.layouts.get(layout_name).map(|layout| layout.clone())
} }
pub fn insert(&self, layout: Rc<dyn LayoutType>) { pub fn insert(&mut self, layout: Rc<dyn LayoutType>) {
self.layouts.insert(layout.name().into(), layout); self.layouts.insert(layout.name().into(), layout);
} }
} }

View file

@ -3,6 +3,7 @@ use std::cell::RefCell;
use std::collections::HashSet; use std::collections::HashSet;
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use ariadne::Label;
use ariadne::Report; use ariadne::Report;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
@ -23,6 +24,7 @@ use crate::elements::paragraph::Paragraph;
use crate::lua::kernel::Kernel; use crate::lua::kernel::Kernel;
use crate::lua::kernel::KernelHolder; use crate::lua::kernel::KernelHolder;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::parser::source::VirtualSource;
use ariadne::Color; use ariadne::Color;
#[derive(Debug)] #[derive(Debug)]
@ -55,39 +57,39 @@ impl ReportColors {
/// The state that is shared with the state's children /// The state that is shared with the state's children
pub struct SharedState { pub struct SharedState {
pub rule_state: RuleStateHolder, pub rule_state: RefCell<RuleStateHolder>,
/// The lua [`Kernel`]s /// The lua [`Kernel`]s
pub kernels: KernelHolder, pub kernels: RefCell<KernelHolder>,
/// The styles /// The styles
pub styles: StyleHolder, pub styles: RefCell<StyleHolder>,
/// The layouts /// The layouts
pub layouts: LayoutHolder, pub layouts: RefCell<LayoutHolder>,
/// The custom styles /// The custom styles
pub custom_styles: CustomStyleHolder, pub custom_styles: RefCell<CustomStyleHolder>,
} }
impl SharedState { impl SharedState {
/// Construct a new empty shared state /// Construct a new empty shared state
pub(self) fn new(parser: &dyn Parser) -> Self { pub(self) fn new(parser: &dyn Parser) -> Self {
let mut s = Self { let s = Self {
rule_state: RuleStateHolder::default(), rule_state: RefCell::new(RuleStateHolder::default()),
kernels: KernelHolder::default(), kernels: RefCell::new(KernelHolder::default()),
styles: StyleHolder::default(), styles: RefCell::new(StyleHolder::default()),
layouts: LayoutHolder::default(), layouts: RefCell::new(LayoutHolder::default()),
custom_styles: CustomStyleHolder::default(), custom_styles: RefCell::new(CustomStyleHolder::default()),
}; };
// Register default kernel // Register default kernel
s.kernels s.kernels.borrow_mut()
.insert("main".to_string(), Kernel::new(parser)); .insert("main".to_string(), Kernel::new(parser));
parser.rules().iter().for_each(|rule| { parser.rules().iter().for_each(|rule| {
rule.register_styles(&mut s.styles); rule.register_styles(&mut *s.styles.borrow_mut());
rule.register_layouts(&mut s.layouts); rule.register_layouts(&mut *s.layouts.borrow_mut());
}); });
s s
@ -106,9 +108,13 @@ pub struct ParserState<'a, 'b> {
matches: RefCell<Vec<(usize, Option<Box<dyn Any>>)>>, matches: RefCell<Vec<(usize, Option<Box<dyn Any>>)>>,
/// State shared among all states /// State shared among all states
pub shared: Rc<RefCell<SharedState>>, pub shared: Rc<SharedState>,
} }
/// Represents the state of the parser
///
/// This state has some shared data from [`SharedState`] which gets shared
/// with the children of that state, see [`ParserState::with_state`]
impl<'a, 'b> ParserState<'a, 'b> { impl<'a, 'b> ParserState<'a, 'b> {
/// Constructs a new state for a given parser with an optional parent /// Constructs a new state for a given parser with an optional parent
/// ///
@ -121,7 +127,7 @@ impl<'a, 'b> ParserState<'a, 'b> {
let shared = if let Some(parent) = &parent { let shared = if let Some(parent) = &parent {
parent.shared.clone() parent.shared.clone()
} else { } else {
Rc::new(RefCell::new(SharedState::new(parser))) Rc::new(SharedState::new(parser))
}; };
Self { Self {
@ -132,76 +138,9 @@ impl<'a, 'b> ParserState<'a, 'b> {
} }
} }
/// Adds a new rule to the current state /// Runs a procedure with a new state that inherits the [`SharedState`] state from [`self`]
/// ///
/// This method will recursively modify the parent states's matches /// Note: When parsing a new document, create a new state, then the parsing process
///
/// # Errors
///
/// Will fail if:
/// * The name for the new rule clashes with an already existing rule
/// * If after is Some(..), not finding the rule to insert after
/// On failure, it is safe to continue using this state, however the added rule won't exists.
/*
pub fn add_rule(
&mut self,
rule: Box<dyn Rule>,
after: Option<&'static str>,
) -> Result<(), String> {
// FIXME: This method should not modify the parser
// Instead we should have some sort of list of references to rules
// Also need to add a sorting key for rules, so they can be automatically registered, then sorted
// TODO2: Should also check for duplicate rules name when creating bindings...
// Error on duplicate rule
if let Some(_) = self
.parser
.rules()
.iter()
.find(|other_rule| other_rule.name() == rule.name())
{
return Err(format!(
"Attempted to introduce duplicate rule: `{}`",
rule.name()
));
}
// Try to insert after
if let Some(after) = after {
let index =
self.parser.rules()
.iter()
.enumerate()
.find(|(_, rule)| rule.name() == after)
.map(|(idx, _)| idx);
if let Some(index) = index {
self.parser.rules_mut().insert(index, rule);
} else {
return Err(format!("Unable to find rule `{after}` to insert after"));
}
} else {
self.parser.rules_mut().push(rule);
}
// Carry out the `matches` modification
fn carry(state: &ParserState) {
state.matches.borrow_mut().push((0, None));
if let Some(parent) = state.parent {
carry(parent);
}
}
carry(self);
// TODO2: Carry on bindings, style, layouts registration... into self.shared
Ok(())
}
*/
/// Runs a procedure with a new state that inherits it's [`SharedState`] state from self
///
/// Note: When parsing a new document, create a default state, then the parsing process
/// creates states using this method /// creates states using this method
pub fn with_state<F, R>(&self, f: F) -> R pub fn with_state<F, R>(&self, f: F) -> R
where where
@ -211,63 +150,6 @@ impl<'a, 'b> ParserState<'a, 'b> {
f(new_state) f(new_state)
} }
fn handle_reports(
&self,
source: Rc<dyn Source>,
reports: Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>,
) {
for mut report in reports {
let mut sources: HashSet<Rc<dyn Source>> = HashSet::new();
fn recurse_source(sources: &mut HashSet<Rc<dyn Source>>, source: Rc<dyn Source>) {
sources.insert(source.clone());
match source.location() {
Some(parent) => {
let parent_source = parent.source();
if sources.get(&parent_source).is_none() {
recurse_source(sources, parent_source);
}
}
None => {}
}
}
report.labels.iter().for_each(|label| {
recurse_source(&mut sources, label.span.0.clone());
});
let cache = sources
.iter()
.map(|source| (source.clone(), source.content().clone()))
.collect::<Vec<(Rc<dyn Source>, String)>>();
cache.iter().for_each(|(source, _)| {
if let Some(location) = source.location() {
if let Some(_s) = source.downcast_ref::<SourceFile>() {
report.labels.push(
Label::new((location.source(), location.start() + 1..location.end()))
.with_message("In file included from here")
.with_order(-1),
);
};
if let Some(_s) = source.downcast_ref::<VirtualSource>() {
let start = location.start()
+ (location.source().content().as_bytes()[location.start()]
== '\n' as u8)
.then_some(1)
.unwrap_or(0);
report.labels.push(
Label::new((location.source(), start..location.end()))
.with_message("In evaluation of")
.with_order(-1),
);
};
}
});
report.eprint(ariadne::sources(cache)).unwrap()
}
}
/// Updates matches from a given start position e.g [`Cursor`] /// Updates matches from a given start position e.g [`Cursor`]
/// ///
/// # Return /// # Return
@ -341,12 +223,11 @@ impl<'a, 'b> ParserState<'a, 'b> {
} }
return (cursor.at(next_pos), return (cursor.at(next_pos),
Some((winner, matches_borrow[0].1.take().unwrap()))) Some((winner, matches_borrow[winner].1.take().unwrap())))
} }
/// Add an [`Element`] to the [`Document`] /// Add an [`Element`] to the [`Document`]
fn push(&mut self, doc: &dyn Document, elem: Box<dyn Element>) { pub fn push(&self, doc: &dyn Document, elem: Box<dyn Element>) {
if elem.kind() == ElemKind::Inline || elem.kind() == ElemKind::Invisible { if elem.kind() == ElemKind::Inline || elem.kind() == ElemKind::Invisible {
let mut paragraph = doc let mut paragraph = doc
.last_element_mut::<Paragraph>() .last_element_mut::<Paragraph>()
@ -363,10 +244,9 @@ impl<'a, 'b> ParserState<'a, 'b> {
} else { } else {
// Process paragraph events // Process paragraph events
if doc.last_element::<Paragraph>().is_some_and(|_| true) { if doc.last_element::<Paragraph>().is_some_and(|_| true) {
self.handle_reports( self.parser.handle_reports(
doc.source(), self.shared.rule_state.borrow_mut()
self.shared.rule_state .on_scope_end(&self, doc, super::state::Scope::PARAGRAPH),
.on_scope_end(&mut self, doc, super::state::Scope::PARAGRAPH),
); );
} }
@ -389,9 +269,6 @@ pub trait Parser {
/// Whether the parser emitted an error during it's parsing process /// Whether the parser emitted an error during it's parsing process
fn has_error(&self) -> bool; fn has_error(&self) -> bool;
/// Add an [`Element`] to the [`Document`]
fn push<'a>(&self, doc: &dyn Document, elem: Box<dyn Element>);
/// Parse [`Source`] into a new [`Document`] /// Parse [`Source`] into a new [`Document`]
/// ///
/// # Errors /// # Errors
@ -453,4 +330,60 @@ pub trait Parser {
Ok(()) Ok(())
} }
fn handle_reports(
&self,
reports: Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>,
) {
for mut report in reports {
let mut sources: HashSet<Rc<dyn Source>> = HashSet::new();
fn recurse_source(sources: &mut HashSet<Rc<dyn Source>>, source: Rc<dyn Source>) {
sources.insert(source.clone());
match source.location() {
Some(parent) => {
let parent_source = parent.source();
if sources.get(&parent_source).is_none() {
recurse_source(sources, parent_source);
}
}
None => {}
}
}
report.labels.iter().for_each(|label| {
recurse_source(&mut sources, label.span.0.clone());
});
let cache = sources
.iter()
.map(|source| (source.clone(), source.content().clone()))
.collect::<Vec<(Rc<dyn Source>, String)>>();
cache.iter().for_each(|(source, _)| {
if let Some(location) = source.location() {
if let Some(_s) = source.downcast_ref::<SourceFile>() {
report.labels.push(
Label::new((location.source(), location.start() + 1..location.end()))
.with_message("In file included from here")
.with_order(-1),
);
};
if let Some(_s) = source.downcast_ref::<VirtualSource>() {
let start = location.start()
+ (location.source().content().as_bytes()[location.start()]
== '\n' as u8)
.then_some(1)
.unwrap_or(0);
report.labels.push(
Label::new((location.source(), start..location.end()))
.with_message("In evaluation of")
.with_order(-1),
);
};
}
});
report.eprint(ariadne::sources(cache)).unwrap()
}
}
} }

View file

@ -1,5 +1,4 @@
use super::layout::LayoutHolder; use super::layout::LayoutHolder;
use super::parser::Parser;
use super::parser::ParserState; use super::parser::ParserState;
use super::source::Cursor; use super::source::Cursor;
use super::source::Source; use super::source::Source;
@ -24,20 +23,20 @@ pub trait Rule: Downcast {
/// Callback when rule matches /// Callback when rule matches
fn on_match<'a>( fn on_match<'a>(
&self, &self,
state: &mut ParserState, state: &ParserState,
document: &'a (dyn Document<'a> + 'a), document: &'a (dyn Document<'a> + 'a),
cursor: Cursor, cursor: Cursor,
match_data: Box<dyn Any>, match_data: Box<dyn Any>,
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>); ) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>);
/// Registers lua bindings /// Registers lua bindings
fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } fn register_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
/// Registers default styles /// Registers default styles
fn register_styles(&self, holder: &mut StyleHolder) {} fn register_styles(&self, _holder: &mut StyleHolder) {}
/// Registers default layouts /// Registers default layouts
fn register_layouts(&self, holder: &mut LayoutHolder) {} fn register_layouts(&self, _holder: &mut LayoutHolder) {}
} }
impl_downcast!(Rule); impl_downcast!(Rule);
@ -57,7 +56,7 @@ pub trait RegexRule {
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
index: usize, index: usize,
state: &mut ParserState, state: &ParserState,
document: &'a (dyn Document<'a> + 'a), document: &'a (dyn Document<'a> + 'a),
token: Token, token: Token,
matches: regex::Captures, matches: regex::Captures,
@ -94,7 +93,7 @@ impl<T: RegexRule + 'static> Rule for T {
fn on_match<'a>( fn on_match<'a>(
&self, &self,
state: &mut ParserState, state: &ParserState,
document: &'a (dyn Document<'a> + 'a), document: &'a (dyn Document<'a> + 'a),
cursor: Cursor, cursor: Cursor,
match_data: Box<dyn Any>, match_data: Box<dyn Any>,

View file

@ -1,3 +1,4 @@
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
@ -31,7 +32,7 @@ pub trait RuleState: Downcast {
/// Callback called when state goes out of scope /// Callback called when state goes out of scope
fn on_remove<'a>( fn on_remove<'a>(
&self, &self,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>>; ) -> Vec<Report<'a, (Rc<dyn Source>, Range<usize>)>>;
} }
@ -46,35 +47,38 @@ impl core::fmt::Debug for dyn RuleState {
/// Object owning all the states /// Object owning all the states
#[derive(Default)] #[derive(Default)]
pub struct RuleStateHolder { pub struct RuleStateHolder {
states: HashMap<String, Rc<dyn RuleState>>, states: HashMap<String, Rc<RefCell<dyn RuleState>>>,
} }
impl RuleStateHolder { impl RuleStateHolder {
// Attempts to push [`state`]. On collision, returns an error with the already present state
pub fn insert( pub fn insert(
&mut self, &mut self,
name: String, name: String,
state: Rc<dyn RuleState>, state: Rc<RefCell<dyn RuleState>>,
) { ) -> Result<Rc<RefCell<dyn RuleState>>, String> {
if self.states.contains_key(name.as_str()) {
return Err(format!("Attempted to insert duplicate RuleState: {name}"));
}
self.states.insert(name, state.clone()); self.states.insert(name, state.clone());
Ok(state)
} }
pub fn get(&self, state_name: &str) -> Option<Rc<dyn RuleState>> { pub fn get(&self, state_name: &str) -> Option<Rc<RefCell<dyn RuleState>>> {
self.states.get(state_name) self.states.get(state_name).map(|state| state.clone())
.map(|state| state.clone())
} }
pub fn on_scope_end( pub fn on_scope_end(
&mut self, &mut self,
state: &mut ParserState, state: &ParserState,
document: &dyn Document, document: &dyn Document,
scope: Scope, scope: Scope,
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> { ) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
let mut reports = vec![]; let mut reports = vec![];
self.states.retain(|_name, rule_state| { self.states.retain(|_name, rule_state| {
if rule_state.scope() >= scope { if rule_state.borrow().scope() >= scope {
rule_state rule_state
.borrow_mut()
.on_remove(state, document) .on_remove(state, document)
.drain(..) .drain(..)
.for_each(|report| reports.push(report)); .for_each(|report| reports.push(report));

View file

@ -32,17 +32,17 @@ pub struct StyleHolder {
impl StyleHolder { impl StyleHolder {
/// Checks if a given style key is registered /// Checks if a given style key is registered
fn is_registered(&self, style_key: &str) -> bool { self.styles.contains_key(style_key) } pub fn is_registered(&self, style_key: &str) -> bool { self.styles.contains_key(style_key) }
/// Gets the current active style for an element /// Gets the current active style for an element
/// NOTE: Will panic if a style is not defined for a given element /// NOTE: Will panic if a style is not defined for a given element
/// If you need to process user input, use [`is_registered`] /// If you need to process user input, use [`is_registered`]
fn current(&self, style_key: &str) -> Rc<dyn ElementStyle> { pub fn current(&self, style_key: &str) -> Rc<dyn ElementStyle> {
self.styles.get(style_key).map(|rc| rc.clone()).unwrap() self.styles.get(style_key).map(|rc| rc.clone()).unwrap()
} }
/// Sets the [`style`] /// Sets the [`style`]
fn set_current(&mut self, style: Rc<dyn ElementStyle>) { pub fn set_current(&mut self, style: Rc<dyn ElementStyle>) {
self.styles.insert(style.key().to_string(), style); self.styles.insert(style.key().to_string(), style);
} }
} }

View file

@ -141,7 +141,9 @@ pub fn parse_paragraph<'a>(
document: &'a dyn Document<'a>, document: &'a dyn Document<'a>,
) -> Result<Box<Paragraph>, &'static str> { ) -> Result<Box<Paragraph>, &'static str> {
let parsed = state.with_state(|new_state| -> Box<dyn Document> { let parsed = state.with_state(|new_state| -> Box<dyn Document> {
new_state.parser.parse(new_state, source.clone(), Some(document)) new_state
.parser
.parse(new_state, source.clone(), Some(document))
}); });
if parsed.content().borrow().len() > 1 { if parsed.content().borrow().len() > 1 {
return Err("Parsed document contains more than a single paragraph"); return Err("Parsed document contains more than a single paragraph");