diff --git a/readme.nml b/readme.nml index 5ee349e..55190a3 100644 --- a/readme.nml +++ b/readme.nml @@ -3,7 +3,7 @@ @'html.css = style.css @tex.main.fontsize = 9 -@tex.main.preamble = \usepackage{xcolor} \\ +@tex.main.preamble = \usepackage{xcolor, amsmath} \\ \definecolor{__color1}{HTML}{d5d5d5} \\ \everymath{\color{__color1}\displaystyle} @tex.main.block_prepend = \color{__color1} @@ -77,7 +77,7 @@ end Evaluating `!` from a kernel: `\%\%` - * `\%\%` → %% + * `\%<[example]! make_bold("Hello, World!")>\%` → %<[example]! make_bold("Hello, World!")>% # Latex diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 5e1768e..2ba9480 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -62,12 +62,12 @@ impl Compiler } } - pub fn header(&self, document: &Document) -> String + pub fn header(&self, document: &dyn Document) -> String { - pub fn get_variable_or_error(document: &Document, var_name: &'static str) -> Option> + pub fn get_variable_or_error(document: &dyn Document, var_name: &'static str) -> Option> { document.get_variable(var_name) - .and_then(|(_, var)| Some(var)) + .and_then(|var| Some(var)) .or_else(|| { println!("Missing variable `{var_name}` in {}", document.source().name()); None @@ -85,7 +85,7 @@ impl Compiler result += format!("{}", self.sanitize(page_title.to_string())).as_str(); } - if let Some((_, css)) = document.get_variable("html.css") + if let Some(css) = document.get_variable("html.css") { result += format!("", self.sanitize(css.to_string())).as_str(); } @@ -101,7 +101,7 @@ impl Compiler result } - pub fn footer(&self, _document: &Document) -> String + pub fn footer(&self, _document: &dyn Document) -> String { let mut result = String::new(); match self.target() @@ -116,10 +116,10 @@ impl Compiler result } - pub fn compile(&self, document: &Document) -> String + pub fn compile(&self, document: &dyn Document) -> String { let mut out = String::new(); - let borrow = document.content.borrow(); + let borrow = document.content().borrow(); // Header out += self.header(document).as_str(); diff --git a/src/document/document.rs b/src/document/document.rs index 5abf275..9f5886e 100644 --- a/src/document/document.rs +++ b/src/document/document.rs @@ -8,16 +8,19 @@ use super::element::Element; use super::variable::Variable; +// TODO: Referenceable rework +// Usize based referencing is not an acceptable method +// if we want to support deltas for the lsp #[derive(Debug)] pub struct Scope { /// List of all referenceable elements in current scope. - /// All elements in this should return a non empty + /// All elements in this should return a non empty pub referenceable: HashMap, pub variables: HashMap>, } impl Scope { - fn new() -> Self { + pub fn new() -> Self { Self { referenceable: HashMap::new(), variables: HashMap::new(), @@ -54,113 +57,82 @@ impl Scope { } } -#[derive(Debug)] -pub struct Document<'a> { - source: Rc, - parent: Option<&'a Document<'a>>, /// Document's parent +pub trait Document<'a>: core::fmt::Debug +{ + /// Gets the document [`Source`] + fn source(&self) -> Rc; - // FIXME: Render these fields private - pub content: RefCell>>, - pub scope: RefCell, -} + /// Gets the document parent (if it exists) + fn parent(&self) -> Option<&'a dyn Document<'a>>; -impl<'a> Document<'a> { - pub fn new(source: Rc, parent: Option<&'a Document<'a>>) -> Self + /// Gets the document content + /// The content is essentially the AST for the document + fn content(&self) -> &RefCell>>; + + /// Gets the document [`Scope`] + fn scope(&self) -> &RefCell; + + /// Pushes a new element into the document's content + fn push(&self, elem: Box) { - Self { - source: source, - parent: parent, - content: RefCell::new(Vec::new()), - scope: RefCell::new(Scope::new()), - } + // TODO: RefTable + + self.content() + .borrow_mut() + .push(elem); } - pub fn source(&self) -> Rc { self.source.clone() } - pub fn parent(&self) -> Option<&Document> { self.parent } - - /// Push an element [`elem`] to content. [`in_paragraph`] is true if a paragraph is active - pub fn push(&self, elem: Box) + /* + fn last_element(&'a self, recurse: bool) -> Option> { - // Add index of current element to scope's reference table - if let Some(referenceable) = elem.as_referenceable() - { - // Only add if referenceable holds a reference - if let Some(ref_name) = referenceable.reference_name() - { - self.scope.borrow_mut().referenceable.insert(ref_name.clone(), self.content.borrow().len()); - } - } - - self.content.borrow_mut().push(elem); - } - - pub fn last_element(&self, recurse: bool) -> Option> - { - let elem = Ref::filter_map(self.content.borrow(), + let elem = Ref::filter_map(self.content().borrow(), |content| content.last() - .and_then(|last| last.downcast_ref::())).ok(); + .and_then(|last| last.downcast_ref::()) + ).ok(); + if elem.is_some() || !recurse { return elem } - match self.parent + match self.parent() { None => None, Some(parent) => parent.last_element(true), } } - pub fn last_element_mut(&self, recurse: bool) -> Option> + fn last_element_mut(&'a self, recurse: bool) -> Option> { - let elem = RefMut::filter_map(self.content.borrow_mut(), - |content| content.last_mut() - .and_then(|last| last.downcast_mut::())).ok(); + let elem = RefMut::filter_map(self.content().borrow_mut(), + |content| content.last_mut()).ok(); if elem.is_some() || !recurse { return elem } - match self.parent + match self.parent() { None => None, Some(parent) => parent.last_element_mut(true), } } + */ - pub fn get_reference(&self, ref_name: &str) -> Option<(&Document<'a>, std::cell::Ref<'_, Box>)> { - match self.scope.borrow().referenceable.get(ref_name) { - // Return if found - Some(elem) => { - return Some((&self, - std::cell::Ref::map(self.content.borrow(), - |m| &m[*elem]))) - }, - - // Continue search recursively - None => match self.parent { - Some(parent) => return parent.get_reference(ref_name), - - // Not found - None => return None, - } - } - } - - pub fn add_variable(&self, variable: Rc) + fn add_variable(&self, variable: Rc) { - self.scope.borrow_mut().variables.insert( + self.scope().borrow_mut().variables.insert( variable.name().to_string(), variable); } - pub fn get_variable>(&self, name: S) -> Option<(&Document<'a>, Rc)> + fn get_variable(&self, name: &str) -> Option> { - match self.scope.borrow().variables.get(name.as_ref()) + match self.scope().borrow().variables.get(name) { Some(variable) => { - return Some((&self, variable.clone())); + return Some(variable.clone()); }, // Continue search recursively - None => match self.parent { + None => match self.parent() { Some(parent) => return parent.get_variable(name), // Not found @@ -169,16 +141,16 @@ impl<'a> Document<'a> { } } - pub fn remove_variable>(&self, name: S) -> Option<(&Document<'a>, Rc)> + fn remove_variable(&self, name: &str) -> Option> { - match self.scope.borrow_mut().variables.remove(name.as_ref()) + match self.scope().borrow_mut().variables.remove(name) { Some(variable) => { - return Some((&self, variable.clone())); + return Some(variable.clone()); }, // Continue search recursively - None => match self.parent { + None => match self.parent() { Some(parent) => return parent.remove_variable(name), // Not found @@ -188,23 +160,44 @@ impl<'a> Document<'a> { } /// Merges [`other`] into [`self`] - pub fn merge(&self, other: Document, merge_as: Option<&String>) + fn merge(&self, content: &RefCell>>, scope: &RefCell, merge_as: Option<&String>) { match merge_as { - Some(merge_as) => self.scope.borrow_mut() + Some(merge_as) => self.scope().borrow_mut() .merge( - &mut *other.scope.borrow_mut(), + &mut *scope.borrow_mut(), merge_as, - self.content.borrow().len()+1), + self.content().borrow().len()+1), _ => {}, } // Content - self.content.borrow_mut().extend((other.content.borrow_mut()) + self.content().borrow_mut().extend((content.borrow_mut()) .drain(..) .map(|value| value)); } } +pub trait DocumentAccessors<'a> +{ + fn last_element(&self) -> Option>; + fn last_element_mut(&self) -> Option>; +} +impl<'a> DocumentAccessors<'a> for dyn Document<'a> + '_ +{ + fn last_element(&self) -> Option> + { + Ref::filter_map(self.content().borrow(), + |content| content.last() + .and_then(|last| last.downcast_ref::())).ok() + } + + fn last_element_mut(&self) -> Option> + { + RefMut::filter_map(self.content().borrow_mut(), + |content| content.last_mut() + .and_then(|last| last.downcast_mut::())).ok() + } +} diff --git a/src/document/element.rs b/src/document/element.rs index e7e9abd..c12cf98 100644 --- a/src/document/element.rs +++ b/src/document/element.rs @@ -48,7 +48,7 @@ pub trait Element: Downcast fn as_referenceable(&self) -> Option<&dyn ReferenceableElement> { None } /// Compiles element - fn compile(&self, compiler: &Compiler, document: &Document) -> Result; + fn compile(&self, compiler: &Compiler, document: &dyn Document) -> Result; } impl_downcast!(Element); diff --git a/src/document/langdocument.rs b/src/document/langdocument.rs new file mode 100644 index 0000000..60b7e14 --- /dev/null +++ b/src/document/langdocument.rs @@ -0,0 +1,38 @@ +use std::{cell::RefCell, rc::Rc}; + +use crate::parser::source::Source; + +use super::{document::{Document, Scope}, element::Element}; + +#[derive(Debug)] +pub struct LangDocument<'a> { + source: Rc, + parent: Option<&'a dyn Document<'a>>, /// Document's parent + + // FIXME: Render these fields private + pub content: RefCell>>, + pub scope: RefCell, +} + +impl<'a> LangDocument<'a> +{ + pub fn new(source: Rc, parent: Option<&'a dyn Document<'a>>) -> Self + { + Self { + source: source, + parent: parent, + content: RefCell::new(Vec::new()), + scope: RefCell::new(Scope::new()), + } + } +} + +impl<'a> Document<'a> for LangDocument<'a> { + fn source(&self) -> Rc { self.source.clone() } + + fn parent(&self) -> Option<&'a dyn Document<'a>> { self.parent.and_then(|p| Some(p as &dyn Document<'a>)) } + + fn content(&self) -> &RefCell>> { &self.content } + + fn scope(&self) -> &RefCell { &self.scope } +} diff --git a/src/document/mod.rs b/src/document/mod.rs index 387c3c9..d80a6b3 100644 --- a/src/document/mod.rs +++ b/src/document/mod.rs @@ -1,3 +1,4 @@ pub mod document; +pub mod langdocument; pub mod element; pub mod variable; diff --git a/src/document/variable.rs b/src/document/variable.rs index 5ce1af4..bae520f 100644 --- a/src/document/variable.rs +++ b/src/document/variable.rs @@ -1,6 +1,6 @@ use std::{path::PathBuf, rc::Rc}; use crate::{elements::text::Text, parser::{parser::Parser, source::{Source, Token, VirtualSource}}}; -use super::{document::Document}; +use super::document::Document; // TODO enforce to_string(from_string(to_string())) == to_string() @@ -15,7 +15,7 @@ pub trait Variable /// Converts variable to a string fn to_string(&self) -> String; - fn parse<'a>(&self, location: Token, parser: &dyn Parser, document: &'a Document); + fn parse<'a>(&self, location: Token, parser: &dyn Parser, document: &'a dyn Document<'a>); } impl core::fmt::Debug for dyn Variable @@ -52,7 +52,7 @@ impl Variable for BaseVariable fn to_string(&self) -> String { self.value.clone() } - fn parse<'a>(&self, _location: Token, parser: &dyn Parser, document: &'a Document) { + fn parse<'a>(&self, _location: Token, parser: &dyn Parser, document: &'a dyn Document<'a>) { let source = Rc::new(VirtualSource::new( self.location().clone(), self.name().to_string(), @@ -90,12 +90,12 @@ impl Variable for PathVariable fn to_string(&self) -> String { self.path.to_str().unwrap().to_string() } - fn parse<'a>(&self, location: Token, parser: &dyn Parser, document: &'a Document){ - // TODO: Avoid copying the location twice... + fn parse<'a>(&self, location: Token, parser: &dyn Parser, document: &'a dyn Document) { + // TODO: Avoid copying the content... // Maybe create a special VirtualSource where the `content()` method // calls `Variable::to_string()` let source = Rc::new(VirtualSource::new( - location.clone(), + location, self.name().to_string(), self.to_string())); diff --git a/src/elements/code.rs b/src/elements/code.rs index e41a6cf..5921a53 100644 --- a/src/elements/code.rs +++ b/src/elements/code.rs @@ -174,7 +174,7 @@ impl Element for Code { fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, compiler: &Compiler, _document: &Document) + fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result { match compiler.target() @@ -226,7 +226,7 @@ impl CodeRule { Self { re: [ Regex::new(r"(?:^|\n)```(?:\[((?:\\.|[^\\\\])*?)\])?(.*?)(?:,(.*))?\n((?:\\(?:.|\n)|[^\\\\])*?)```").unwrap(), - Regex::new(r"``(?:\[((?:\\.|[^\[\]\\])*?)\])?(?:(.*)(?:\n|,))?((?:\\(?:.|\n)|[^\\\\])*?)``").unwrap(), + Regex::new(r"``(?:\[((?:\\.|[^\[\]\\])*?)\])?(?:(.*?)(?:\n|,))?((?:\\(?:.|\n)|[^\\\\])*?)``").unwrap(), ], properties: PropertyParser::new(props) } @@ -239,7 +239,7 @@ impl RegexRule for CodeRule fn regexes(&self) -> &[regex::Regex] { &self.re } - fn on_regex_match(&self, index: usize, parser: &dyn Parser, document: &Document, token: Token, matches: Captures) + fn on_regex_match<'a>(&self, index: usize, parser: &dyn Parser, document: &'a dyn Document, token: Token, matches: Captures) -> Vec, Range)>> { let mut reports = vec![]; @@ -328,7 +328,7 @@ impl RegexRule for CodeRule } let theme = document.get_variable("code.theme") - .and_then(|(_doc, var)| Some(var.to_string())); + .and_then(|var| Some(var.to_string())); if index == 0 // Block { diff --git a/src/elements/comment.rs b/src/elements/comment.rs index 021f412..a75e21d 100644 --- a/src/elements/comment.rs +++ b/src/elements/comment.rs @@ -1,8 +1,8 @@ use mlua::{Function, Lua}; use regex::{Captures, Regex}; -use crate::parser::{parser::Parser, rule::RegexRule, source::{Source, Token}}; +use crate::{document::document::Document, parser::{parser::Parser, rule::RegexRule, source::{Source, Token}}}; use ariadne::{Report, Label, ReportKind}; -use crate::{compiler::compiler::Compiler, document::{document::Document, element::{ElemKind, Element}}}; +use crate::{compiler::compiler::Compiler, document::element::{ElemKind, Element}}; use std::{ops::Range, rc::Rc}; #[derive(Debug)] @@ -24,7 +24,7 @@ impl Element for Comment fn kind(&self) -> ElemKind { ElemKind::Invisible } fn element_name(&self) -> &'static str { "Comment" } fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, _compiler: &Compiler, _document: &Document) + fn compile(&self, _compiler: &Compiler, _document: &dyn Document) -> Result { Ok("".to_string()) } @@ -45,7 +45,7 @@ impl RegexRule for CommentRule { fn regexes(&self) -> &[Regex] { &self.re } - fn on_regex_match(&self, _: usize, parser: &dyn Parser, document: &Document, token: Token, matches: Captures) + fn on_regex_match<'a>(&self, _: usize, parser: &dyn Parser, document: &'a dyn Document, token: Token, matches: Captures) -> Vec, Range)>> { let mut reports = vec![]; @@ -73,7 +73,7 @@ impl RegexRule for CommentRule { parser.push(document, Box::new( Comment::new( token.clone(), - content + content ) )); diff --git a/src/elements/import.rs b/src/elements/import.rs index 393e689..1fc089d 100644 --- a/src/elements/import.rs +++ b/src/elements/import.rs @@ -1,8 +1,7 @@ use mlua::{Function, Lua}; -use regex::Regex; -use crate::parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, SourceFile, Token}}; +use regex::{Captures, Regex}; +use crate::{document::document::{DocumentAccessors, Document}, parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, SourceFile, Token}}}; use ariadne::{Report, Fmt, Label, ReportKind}; -use crate::document::document::Document; use std::{ops::Range, rc::Rc}; use super::paragraph::Paragraph; @@ -35,8 +34,8 @@ impl RegexRule for ImportRule { fn regexes(&self) -> &[Regex] { &self.re } - fn on_regex_match(&self, _: usize, parser: &dyn Parser, document: &Document, token: Token, matches: regex::Captures) -> Vec, Range)>> - { + fn on_regex_match<'a>(&self, _: usize, parser: &dyn Parser, document: &'a dyn Document<'a>, token: Token, matches: Captures) + -> Vec, Range)>> { let mut result = vec![]; // Path @@ -138,13 +137,11 @@ impl RegexRule for ImportRule { } }; - // TODO - let import_doc = parser.parse(import, Some(&document)); - - document.merge(import_doc, Some(&import_as)); + let import_doc = parser.parse(import, Some(document)); + document.merge(import_doc.content(), import_doc.scope(), Some(&import_as)); // Close paragraph - if document.last_element::(false).is_some() + if document.last_element::().is_some() { parser.push(document, Box::new(Paragraph::new( Token::new(token.end()..token.end(), token.source()) diff --git a/src/elements/link.rs b/src/elements/link.rs index 8a5bf0a..24b1188 100644 --- a/src/elements/link.rs +++ b/src/elements/link.rs @@ -1,5 +1,5 @@ use mlua::{Function, Lua}; -use regex::Regex; +use regex::{Captures, Regex}; use serde::{Deserialize, Serialize}; use crate::parser::{parser::Parser, rule::RegexRule, source::{Source, Token}, util}; use ariadne::{Report, Fmt, Label, ReportKind}; @@ -26,7 +26,7 @@ impl Element for Link fn kind(&self) -> ElemKind { ElemKind::Inline } fn element_name(&self) -> &'static str { "Link" } fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, compiler: &Compiler, _document: &Document) -> Result { + fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result { match compiler.target() { Target::HTML => { @@ -51,7 +51,7 @@ pub struct LinkRule { impl LinkRule { pub fn new() -> Self { - Self { re: [Regex::new(r"(?:^|\n)```(.*?)(?:,(.*))?\n((?:\\.|[^\[\]\\])*?)```").unwrap()] } + Self { re: [Regex::new(r"\[((?:\\.|[^\\\\])*?)\]\(((?:\\.|[^\\\\])*?)\)").unwrap()] } } } @@ -60,8 +60,8 @@ impl RegexRule for LinkRule { fn regexes(&self) -> &[Regex] { &self.re } - fn on_regex_match(&self, _: usize, parser: &dyn Parser, document: &Document, token: Token, matches: regex::Captures) -> Vec, Range)>> - { + fn on_regex_match<'a>(&self, _: usize, parser: &dyn Parser, document: &'a dyn Document, token: Token, matches: Captures) + -> Vec, Range)>> { let mut result = vec![]; let link_name = match matches.get(1) { diff --git a/src/elements/list.rs b/src/elements/list.rs index dd05ef8..a73b7ae 100644 --- a/src/elements/list.rs +++ b/src/elements/list.rs @@ -1,6 +1,6 @@ use std::{any::Any, cell::Ref, ops::Range, rc::Rc}; -use crate::{compiler::compiler::{Compiler, Target}, document::{document::Document, element::{ElemKind, Element}}, parser::{parser::Parser, rule::Rule, source::{Cursor, Source, Token, VirtualSource}}}; +use crate::{compiler::compiler::{Compiler, Target}, document::{document::{Document, DocumentAccessors}, element::{ElemKind, Element}}, parser::{parser::Parser, rule::Rule, source::{Cursor, Source, Token, VirtualSource}}}; use ariadne::{Label, Report, ReportKind}; use mlua::{Function, Lua}; use regex::Regex; @@ -57,7 +57,7 @@ impl Element for List fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, compiler: &Compiler, document: &Document) -> Result { + fn compile(&self, compiler: &Compiler, document: &dyn Document) -> Result { match compiler.target() { Target::HTML => { @@ -196,10 +196,11 @@ impl ListRule { } - fn parse_depth(depth: &str, document: &Document) -> Vec<(bool, usize)> + fn parse_depth(depth: &str, document: &dyn Document) -> Vec<(bool, usize)> { let mut parsed = vec![]; - let prev_entry = document.last_element::(true) + // FIXME: Previous iteration used to recursively retrieve the list indent + let prev_entry = document.last_element::() .and_then(|list| Ref::filter_map(list, |m| m.entries.last() ).ok() ) .and_then(|entry| Ref::filter_map(entry, |e| Some(&e.numbering)).ok() ); @@ -246,7 +247,8 @@ impl Rule for ListRule |m| Some((m.start(), Box::new([false;0]) as Box)) ) } - fn on_match<'a>(&self, parser: &dyn Parser, document: &'a Document<'a>, cursor: Cursor, _match_data: Option>) -> (Cursor, Vec, Range)>>) { + fn on_match<'a>(&self, parser: &dyn Parser, document: &'a dyn Document<'a>, cursor: Cursor, _match_data: Option>) + -> (Cursor, Vec, Range)>>) { let mut reports = vec![]; let content = cursor.source.content(); let (end_cursor, numbering, source) = match self.start_re.captures_at(content, cursor.pos) { @@ -310,8 +312,8 @@ impl Rule for ListRule }, }; - let parsed_entry = parser.parse(Rc::new(source), Some(&document)); - let mut parsed_paragraph = parsed_entry.last_element_mut::(false).unwrap(); // Extract content from paragraph + let parsed_entry = parser.parse(Rc::new(source), Some(document)); + let mut parsed_paragraph = parsed_entry.last_element_mut::().unwrap(); // Extract content from paragraph let entry = ListEntry::new( Token::new(cursor.pos..end_cursor.pos, cursor.source.clone()), numbering, @@ -319,14 +321,14 @@ impl Rule for ListRule ); // Ger previous list, if none insert a new list - let mut list = match document.last_element_mut::(false) + let mut list = match document.last_element_mut::() { Some(last) => last, None => { parser.push(document, Box::new(List::new( Token::new(cursor.pos..end_cursor.pos, cursor.source.clone())))); - document.last_element_mut::(false).unwrap() + document.last_element_mut::().unwrap() } }; list.push(entry); diff --git a/src/elements/paragraph.rs b/src/elements/paragraph.rs index c170160..65861ce 100644 --- a/src/elements/paragraph.rs +++ b/src/elements/paragraph.rs @@ -54,7 +54,7 @@ impl Element for Paragraph fn to_string(&self) -> String { format!("{:#?}", self) } - fn compile(&self, compiler: &Compiler, document: &Document) -> Result { + fn compile(&self, compiler: &Compiler, document: &dyn Document) -> Result { if self.content.is_empty() { return Ok(String::new()) } match compiler.target() @@ -109,7 +109,7 @@ impl Rule for ParagraphRule .and_then(|m| Some((m.start(), Box::new([false;0]) as Box)) ) } - fn on_match(&self, parser: &dyn Parser, document: &Document, cursor: Cursor, _match_data: Option>) + fn on_match(&self, parser: &dyn Parser, document: &dyn Document, cursor: Cursor, _match_data: Option>) -> (Cursor, Vec, Range)>>) { let end_cursor = match self.re.captures_at(cursor.source.content(), cursor.pos) diff --git a/src/elements/raw.rs b/src/elements/raw.rs index c24df80..3f51085 100644 --- a/src/elements/raw.rs +++ b/src/elements/raw.rs @@ -1,15 +1,14 @@ -use mlua::{Function, Lua}; +use mlua::{Error::BadArgument, Function, Lua}; use regex::{Captures, Regex}; -use crate::{compiler::compiler::Compiler, document::element::{ElemKind, Element}, parser::{parser::Parser, rule::RegexRule, source::{Source, Token}, util::{self, Property, PropertyParser}}}; +use crate::{compiler::compiler::Compiler, document::{document::Document, element::{ElemKind, Element}}, lua::kernel::CTX, parser::{parser::Parser, rule::RegexRule, source::{Source, Token}, util::{self, Property, PropertyParser}}}; use ariadne::{Fmt, Label, Report, ReportKind}; -use crate::document::document::Document; -use std::{collections::HashMap, ops::Range, rc::Rc, str::FromStr}; +use std::{collections::HashMap, ops::Range, rc::Rc, str::FromStr, sync::Arc}; #[derive(Debug)] struct Raw { - location: Token, - kind: ElemKind, - content: String, + pub(self) location: Token, + pub(self) kind: ElemKind, + pub(self) content: String, } impl Raw { @@ -26,7 +25,7 @@ impl Element for Raw { fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, compiler: &Compiler, _document: &Document) -> Result { + fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result { Ok(self.content.clone()) } } @@ -59,7 +58,7 @@ impl RegexRule for RawRule fn regexes(&self) -> &[regex::Regex] { &self.re } - fn on_regex_match(&self, _index: usize, parser: &dyn Parser, document: &Document, token: Token, matches: Captures) + fn on_regex_match(&self, _index: usize, parser: &dyn Parser, document: &dyn Document, token: Token, matches: Captures) -> Vec, Range)>> { let mut reports = vec![]; @@ -154,15 +153,43 @@ impl RegexRule for RawRule } }; - parser.push(document, Box::new(Raw::new( - token.clone(), - raw_kind, - raw_content - ))); + parser.push(document, Box::new(Raw { + location: token.clone(), + kind: raw_kind, + content: raw_content + })); reports } - // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { + let mut bindings = vec![]; + + bindings.push(("push".to_string(), lua.create_function( + |_, (kind, content): (String, String)| { + // Validate kind + let kind = match ElemKind::from_str(kind.as_str()) + { + Ok(kind) => kind, + Err(e) => return Err(BadArgument { + to: Some("push".to_string()), + pos: 1, + name: Some("kind".to_string()), + cause: Arc::new(mlua::Error::external( + format!("Wrong section kind specified: {e}")))}) + }; + + CTX.with_borrow(|ctx| ctx.as_ref().map(|ctx| { + ctx.parser.push(ctx.document, Box::new(Raw { + location: ctx.location.clone(), + kind, + content, + })); + })); + + Ok(()) + }).unwrap())); + + bindings + } } diff --git a/src/elements/script.rs b/src/elements/script.rs index 93bd96d..fa083ff 100644 --- a/src/elements/script.rs +++ b/src/elements/script.rs @@ -1,8 +1,7 @@ use mlua::{Function, Lua}; use regex::{Captures, Regex}; -use crate::{lua::kernel::{Kernel, KernelContext, KernelHolder}, parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, Token, VirtualSource}, util}}; +use crate::{document::document::Document, lua::kernel::{Kernel, KernelContext, KernelHolder}, parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, Token, VirtualSource}, util}}; use ariadne::{Fmt, Label, Report, ReportKind}; -use crate::document::document::Document; use std::{ops::Range, rc::Rc}; use super::text::Text; @@ -18,7 +17,7 @@ impl ScriptRule { Self { re: [ Regex::new(r"(?:^|\n)@<(?:(.*)\n?)((?:\\.|[^\\\\])*?)(?:\n?)>@").unwrap(), - Regex::new(r"%<([^\s[:alpha:]])?(?:\[(.*?)\])?((?:\\.|[^\\\\])*?)(?:\n?)>%").unwrap() + Regex::new(r"%<(?:\[(.*?)\])?([^\s[:alpha:]])?((?:\\.|[^\\\\])*?)(?:\n?)>%").unwrap() ], eval_kinds: [ ("", "Eval"), @@ -60,11 +59,11 @@ impl RegexRule for ScriptRule fn regexes(&self) -> &[regex::Regex] { &self.re } - fn on_regex_match(&self, index: usize, parser: &dyn Parser, document: &Document, token: Token, matches: Captures) + fn on_regex_match<'a>(&self, index: usize, parser: &dyn Parser, document: &'a dyn Document<'a>, token: Token, matches: Captures) -> Vec, Range)>> { let mut reports = vec![]; - let kernel_name = match matches.get(if index == 0 {1} else {2}) { + let kernel_name = match matches.get(1) { None => "main".to_string(), Some(name) => { match ScriptRule::validate_kernel_name(parser.colors(), name.as_str()) @@ -84,13 +83,7 @@ impl RegexRule for ScriptRule } } }; - let kernel_name = matches.get(if index == 0 {1} else {2}) - .and_then(|name| { - let trimmed = name.as_str().trim_start().trim_end(); - (!trimmed.is_empty()).then_some(trimmed) - }) - .unwrap_or("main"); - let kernel = parser.get_kernel(kernel_name).unwrap_or_else(|| { + let kernel = parser.get_kernel(kernel_name.as_str()).unwrap_or_else(|| { parser.insert_kernel(kernel_name.to_string(), Kernel::new(parser)) }); @@ -143,7 +136,7 @@ impl RegexRule for ScriptRule else // Eval { // Validate kind - let kind = match matches.get(1) { + let kind = match matches.get(2) { None => 0, Some(kind) => { match self.validate_kind(parser.colors(), kind.as_str()) diff --git a/src/elements/section.rs b/src/elements/section.rs index 4ea478d..9af30a6 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -1,8 +1,8 @@ use mlua::{Error::BadArgument, Function, Lua}; use regex::Regex; -use crate::{compiler::compiler::Target, lua::kernel::CTX, parser::{parser::Parser, rule::RegexRule, source::{Source, Token}}}; +use crate::{compiler::compiler::Target, document::document::Document, lua::kernel::CTX, parser::{parser::Parser, rule::RegexRule, source::{Source, Token}}}; use ariadne::{Report, Fmt, Label, ReportKind}; -use crate::{compiler::compiler::Compiler, document::{document::Document, element::{ElemKind, Element, ReferenceableElement}}}; +use crate::{compiler::compiler::Compiler, document::element::{ElemKind, Element, ReferenceableElement}}; use std::{ops::Range, rc::Rc, sync::Arc}; #[derive(Debug)] @@ -21,7 +21,7 @@ impl Element for Section fn element_name(&self) -> &'static str { "Section" } fn to_string(&self) -> String { format!("{self:#?}") } fn as_referenceable(&self) -> Option<&dyn ReferenceableElement> { Some(self) } - fn compile(&self, compiler: &Compiler, _document: &Document) -> Result { + fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result { match compiler.target() { Target::HTML => { @@ -61,7 +61,7 @@ impl RegexRule for SectionRule { fn regexes(&self) -> &[Regex] { &self.re } - fn on_regex_match(&self, _: usize, parser: &dyn Parser, document: &Document, token: Token, matches: regex::Captures) -> Vec, Range)>> + fn on_regex_match(&self, _: usize, parser: &dyn Parser, document: &dyn Document, token: Token, matches: regex::Captures) -> Vec, Range)>> { let mut result = vec![]; let section_depth = match matches.get(1) @@ -89,6 +89,7 @@ impl RegexRule for SectionRule { // [Optional] Reference name let section_refname = matches.get(2).map_or_else(|| None, |refname| { + /* TODO: Wait for reference rework // Check for duplicate reference if let Some((ref_doc, reference)) = document.get_reference(refname.as_str()) { @@ -112,6 +113,7 @@ impl RegexRule for SectionRule { .with_note(format!("Previous reference was overwritten")) .finish()); } + */ Some(refname.as_str().to_string()) }); diff --git a/src/elements/style.rs b/src/elements/style.rs index 6af05a1..a3248b1 100644 --- a/src/elements/style.rs +++ b/src/elements/style.rs @@ -1,8 +1,7 @@ use mlua::{Function, Lua}; use regex::{Captures, Regex}; -use crate::{compiler::compiler::{Compiler, Target}, document::element::{ElemKind, Element}, parser::{parser::Parser, rule::RegexRule, source::{Source, Token}, state::State}}; +use crate::{compiler::compiler::{Compiler, Target}, document::{document::{DocumentAccessors, Document}, element::{ElemKind, Element}}, parser::{parser::Parser, rule::RegexRule, source::{Source, Token}, state::State}}; use ariadne::{Fmt, Label, Report, ReportKind}; -use crate::document::document::Document; use crate::parser::state::Scope; use std::{cell::RefCell, ops::Range, rc::Rc}; use lazy_static::lazy_static; @@ -29,7 +28,7 @@ impl Element for Style fn kind(&self) -> ElemKind { ElemKind::Inline } fn element_name(&self) -> &'static str { "Section" } fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, compiler: &Compiler, _document: &Document) -> Result { + fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result { match compiler.target() { Target::HTML => { @@ -66,7 +65,7 @@ impl State for StyleState { fn scope(&self) -> Scope { Scope::PARAGRAPH } - fn on_remove<'a>(&self, parser: &dyn Parser, document: &Document) -> Vec, Range)>> { + fn on_remove<'a>(&self, parser: &dyn Parser, document: &dyn Document) -> Vec, Range)>> { let mut result = Vec::new(); self.toggled .iter() @@ -80,7 +79,7 @@ impl State for StyleState //let active_range = range.start .. paragraph.location().end()-1; - let paragraph = document.last_element::(false).unwrap(); + let paragraph = document.last_element::().unwrap(); let paragraph_end = paragraph.content.last() .and_then(|last| Some((last.location().source(), last.location().end()-1 .. last.location().end()))) .unwrap(); @@ -145,7 +144,7 @@ impl RegexRule for StyleRule fn regexes(&self) -> &[regex::Regex] { &self.re } - fn on_regex_match(&self, index: usize, parser: &dyn Parser, document: &Document, token: Token, _matches: Captures) -> Vec, Range)>> { + fn on_regex_match(&self, index: usize, parser: &dyn Parser, document: &dyn Document, token: Token, _matches: Captures) -> Vec, Range)>> { let result = vec![]; let query = parser.state().query(&STATE_NAME); diff --git a/src/elements/tex.rs b/src/elements/tex.rs index 9900233..5be07ad 100644 --- a/src/elements/tex.rs +++ b/src/elements/tex.rs @@ -123,7 +123,7 @@ impl Element for Tex { fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, compiler: &Compiler, document: &Document) + fn compile(&self, compiler: &Compiler, document: &dyn Document) -> Result { match compiler.target() { @@ -136,18 +136,18 @@ impl Element for Tex { } }); - let exec = document.get_variable(format!("tex.{}.exec", self.env)) - .map_or("latex2svg".to_string(), |(_, var)| var.to_string()); + let exec = document.get_variable(format!("tex.{}.exec", self.env).as_str()) + .map_or("latex2svg".to_string(), |var| var.to_string()); // FIXME: Because fontsize is passed as an arg, verify that it cannot be used to execute python/shell code - let fontsize = document.get_variable(format!("tex.{}.fontsize", self.env)) - .map_or("12".to_string(), |(_, var)| var.to_string()); - let preamble = document.get_variable(format!("tex.{}.preamble", self.env)) - .map_or("".to_string(), |(_, var)| var.to_string()); + let fontsize = document.get_variable(format!("tex.{}.fontsize", self.env).as_str()) + .map_or("12".to_string(), |var| var.to_string()); + let preamble = document.get_variable(format!("tex.{}.preamble", self.env).as_str()) + .map_or("".to_string(), |var| var.to_string()); let prepend = if self.block == TexKind::Inline { "".to_string() } else { - document.get_variable(format!("tex.{}.block_prepend", self.env)) - .map_or("".to_string(), |(_, var)| var.to_string()+"\n") + document.get_variable(format!("tex.{}.block_prepend", self.env).as_str()) + .map_or("".to_string(), |var| var.to_string()+"\n") }; let latex = match self.block @@ -205,7 +205,7 @@ impl RegexRule for TexRule fn regexes(&self) -> &[regex::Regex] { &self.re } - fn on_regex_match(&self, index: usize, parser: &dyn Parser, document: &Document, token: Token, matches: Captures) + fn on_regex_match(&self, index: usize, parser: &dyn Parser, document: &dyn Document, token: Token, matches: Captures) -> Vec, Range)>> { let mut reports = vec![]; diff --git a/src/elements/text.rs b/src/elements/text.rs index 1eed8a5..ea765d5 100644 --- a/src/elements/text.rs +++ b/src/elements/text.rs @@ -1,6 +1,6 @@ use mlua::{Function, Lua}; -use crate::{compiler::compiler::Compiler, document::{document::Document, element::{ElemKind, Element}}, lua::kernel::CTX, parser::{rule::Rule, source::Token}}; +use crate::{compiler::compiler::Compiler, document::{document::Document, element::{ElemKind, Element}}, lua::kernel::CTX, parser::{parser::Parser, rule::Rule, source::Token}}; #[derive(Debug)] pub struct Text @@ -27,7 +27,7 @@ impl Element for Text fn element_name(&self) -> &'static str { "Text" } fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, compiler: &Compiler, _document: &Document) -> Result { + fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result { Ok(compiler.sanitize(self.content.as_str())) } } @@ -41,11 +41,10 @@ impl Rule for TextRule fn next_match(&self, cursor: &crate::parser::source::Cursor) -> Option<(usize, Box)> { None } - fn on_match(&self, parser: &dyn crate::parser::parser::Parser, document: &crate::document::document::Document, cursor: crate::parser::source::Cursor, match_data: Option>) -> (crate::parser::source::Cursor, Vec, std::ops::Range)>>) { panic!("Text canno match"); } + fn on_match(&self, parser: &dyn Parser, document: &dyn Document, cursor: crate::parser::source::Cursor, match_data: Option>) -> (crate::parser::source::Cursor, Vec, std::ops::Range)>>) { panic!("Text canno match"); } fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { let mut bindings = vec![]; - bindings.push(("push".to_string(), lua.create_function( |_, content: String| { CTX.with_borrow(|ctx| ctx.as_ref().map(|ctx| { diff --git a/src/elements/variable.rs b/src/elements/variable.rs index 0a63daa..60fba59 100644 --- a/src/elements/variable.rs +++ b/src/elements/variable.rs @@ -1,8 +1,8 @@ use mlua::{Function, Lua}; use regex::Regex; -use crate::parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, Token}}; +use crate::{document::document::Document, parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, Token}}}; use ariadne::{Report, Fmt, Label, ReportKind}; -use crate::document::{document::Document, variable::{BaseVariable, PathVariable, Variable}}; +use crate::document::variable::{BaseVariable, PathVariable, Variable}; use std::{ops::Range, rc::Rc}; pub struct VariableRule { @@ -91,7 +91,7 @@ impl RegexRule for VariableRule { - fn on_regex_match(&self, _: usize, parser: &dyn Parser, document: &Document, token: Token, matches: regex::Captures) -> Vec, Range)>> + fn on_regex_match<'a>(&self, _: usize, parser: &dyn Parser, document: &'a dyn Document, token: Token, matches: regex::Captures) -> Vec, Range)>> { let mut result = vec![]; // [Optional] variable kind @@ -223,7 +223,7 @@ impl RegexRule for VariableSubstitutionRule fn regexes(&self) -> &[regex::Regex] { &self.re } - fn on_regex_match(&self, _index: usize, parser: &dyn Parser, document: &Document, token: Token, matches: regex::Captures) -> Vec, Range)>> { + fn on_regex_match<'a>(&self, _index: usize, parser: &dyn Parser, document: &'a dyn Document<'a>, token: Token, matches: regex::Captures) -> Vec, Range)>> { let mut result = vec![]; let variable = match matches.get(1) @@ -307,27 +307,13 @@ impl RegexRule for VariableSubstitutionRule .finish()); return result; } - Some((_, var)) => var, + Some(var) => var, } }, _ => panic!("Unknown error") }; variable.parse(token, parser, document); - //let parsed = variable.parse( - // token, - // parser, - // document - //); - ////document.merge(parsed, None); - //parsed.content.borrow_mut() - // .drain(..) - // .for_each(|elem| parser.push(document, elem)); - //parser.push(document, ) - - // TODO: Full rework of document - // parser shound parse into previous document, and not into a new document - // This should prevent having to sue `recurse: bool` in the last_element getters return result; } diff --git a/src/lsp/semantic.rs b/src/lsp/semantic.rs index 49418ea..cebcf68 100644 --- a/src/lsp/semantic.rs +++ b/src/lsp/semantic.rs @@ -71,20 +71,36 @@ pub fn semantic_token_from_document(document: &Document) -> Vec source: source.clone() }; - document.content.borrow() - .iter() - .for_each(|elem| { - if let Some(paragraph) = elem.downcast_ref::() - { - paragraph.content - .iter() - .for_each(|elem| provide(&mut semantic_tokens, &mut cursor, elem)); - } - else - { - provide(&mut semantic_tokens, &mut cursor, elem); - } - }); + semantic_tokens.push(SemanticToken { + delta_line: 1, + delta_start: 1, + length: 5, + token_type: 0, + token_modifiers_bitset: 0, + }); + + semantic_tokens.push(SemanticToken { + delta_line: 1, + delta_start: 1, + length: 5, + token_type: 1, + token_modifiers_bitset: 0, + }); + + //document.content.borrow() + // .iter() + // .for_each(|elem| { + // if let Some(paragraph) = elem.downcast_ref::() + // { + // paragraph.content + // .iter() + // .for_each(|elem| provide(&mut semantic_tokens, &mut cursor, elem)); + // } + // else + // { + // provide(&mut semantic_tokens, &mut cursor, elem); + // } + // }); semantic_tokens } diff --git a/src/lua/kernel.rs b/src/lua/kernel.rs index 7ac6b7b..8e0bb81 100644 --- a/src/lua/kernel.rs +++ b/src/lua/kernel.rs @@ -1,19 +1,19 @@ -use std::{cell::{RefCell, RefMut}, rc::Rc}; +use std::cell::{RefCell, RefMut}; -use mlua::{Error, FromLua, Lua, UserData, UserDataMethods}; +use mlua::Lua; use crate::{document::document::Document, parser::{parser::Parser, source::Token}}; -pub struct KernelContext<'a> +pub struct KernelContext<'a, 'b> { pub location: Token, pub parser: &'a dyn Parser, - pub document: &'a Document<'a>, + pub document: &'b dyn Document<'b>, //pub parser: &'a dyn Parser, } thread_local! { - pub static CTX: RefCell>> = RefCell::new(None); + pub static CTX: RefCell>> = RefCell::new(None); } #[derive(Debug)] @@ -23,7 +23,6 @@ pub struct Kernel } impl Kernel { - // TODO: Take parser as arg and // iterate over the rules // to find export the bindings (if some) diff --git a/src/main.rs b/src/main.rs index 089dcf3..5600898 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,26 +75,27 @@ fn main() { if debug_opts.contains(&"ast".to_string()) { println!("-- BEGIN AST DEBUGGING --"); - doc.content.borrow().iter().for_each(|elem| { + doc.content().borrow().iter().for_each(|elem| { println!("{}", (elem).to_string()) }); println!("-- END AST DEBUGGING --"); } - if debug_opts.contains(&"ref".to_string()) - { - println!("-- BEGIN REFERENCES DEBUGGING --"); - let sc = doc.scope.borrow(); - sc.referenceable.iter().for_each(|(name, pos)| { - println!(" - {name}: `{:#?}`", doc.content.borrow()[*pos]); - }); - println!("-- END REFERENCES DEBUGGING --"); - } + // TODO + //if debug_opts.contains(&"ref".to_string()) + //{ + // println!("-- BEGIN REFERENCES DEBUGGING --"); + // let sc = doc.scope.borrow(); + // sc.referenceable.iter().for_each(|(name, pos)| { + // println!(" - {name}: `{:#?}`", doc.content.borrow()[*pos]); + // }); + // println!("-- END REFERENCES DEBUGGING --"); + //} if debug_opts.contains(&"var".to_string()) { println!("-- BEGIN VARIABLES DEBUGGING --"); - let sc = doc.scope.borrow(); + let sc = doc.scope().borrow(); sc.variables.iter().for_each(|(_name, var)| { println!(" - `{:#?}`", var); }); @@ -103,7 +104,7 @@ fn main() { let compiler = Compiler::new(compiler::compiler::Target::HTML, db_path); - let out = compiler.compile(&doc); + let out = compiler.compile(doc.as_ref()); std::fs::write("a.html", out).unwrap(); } diff --git a/src/parser/langparser.rs b/src/parser/langparser.rs index 2789a39..80f000f 100644 --- a/src/parser/langparser.rs +++ b/src/parser/langparser.rs @@ -1,8 +1,8 @@ -use std::{cell::{RefCell, RefMut}, collections::{HashMap, HashSet}, ops::Range, rc::Rc}; +use std::{cell::{Ref, RefCell, RefMut}, collections::{HashMap, HashSet}, ops::Range, rc::Rc}; use ariadne::{Label, Report}; -use crate::{document::{document::Document, element::{ElemKind, Element}}, elements::{paragraph::Paragraph, registrar::register, text::Text}, lua::kernel::{Kernel, KernelHolder}, parser::source::{SourceFile, VirtualSource}}; +use crate::{document::{document::{DocumentAccessors, Document}, element::{ElemKind, Element}, langdocument::LangDocument}, elements::{paragraph::Paragraph, registrar::register, text::Text}, lua::kernel::{Kernel, KernelHolder}, parser::source::{SourceFile, VirtualSource}}; use super::{parser::{Parser, ReportColors}, rule::Rule, source::{Cursor, Source, Token}, state::StateHolder, util}; @@ -132,14 +132,14 @@ impl Parser for LangParser fn state_mut(&self) -> std::cell::RefMut<'_, StateHolder> { self.state.borrow_mut() } /// Add an [`Element`] to the [`Document`] - fn push<'a>(&self, doc: &'a Document<'a>, elem: Box) + fn push<'a>(&self, doc: &dyn Document, elem: Box) { if elem.kind() == ElemKind::Inline || elem.kind() == ElemKind::Invisible { - let mut paragraph = doc.last_element_mut::(false) + let mut paragraph = doc.last_element_mut::() .or_else(|| { doc.push(Box::new(Paragraph::new(elem.location().clone()))); - doc.last_element_mut::(false) + doc.last_element_mut::() }).unwrap(); paragraph.push(elem); @@ -147,20 +147,20 @@ impl Parser for LangParser else { // Process paragraph events - if doc.last_element_mut::(false) + if doc.last_element::() .is_some_and(|_| true) { self.handle_reports(doc.source(), - self.state_mut().on_scope_end(self, &doc, super::state::Scope::PARAGRAPH)); + self.state_mut().on_scope_end(self, doc, super::state::Scope::PARAGRAPH)); } doc.push(elem); } } - fn parse<'a>(&self, source: Rc, parent: Option<&'a Document<'a>>) -> Document<'a> + fn parse<'a>(&self, source: Rc, parent: Option<&'a dyn Document<'a>>) -> Box+'a> { - let doc = Document::new(source.clone(), parent); + let doc = LangDocument::new(source.clone(), parent); let mut matches = Vec::new(); for _ in 0..self.rules.len() { matches.push((0usize, None)); @@ -169,10 +169,10 @@ impl Parser for LangParser let content = source.content(); let mut cursor = Cursor::new(0usize, doc.source()); // Cursor in file - if parent.is_some() // Terminate parent's paragraph state + if let Some(parent) = parent // Terminate parent's paragraph state { - self.handle_reports(parent.as_ref().unwrap().source(), - self.state_mut().on_scope_end(self, parent.as_ref().unwrap(), super::state::Scope::PARAGRAPH)); + self.handle_reports(parent.source(), + self.state_mut().on_scope_end(self, parent, super::state::Scope::PARAGRAPH)); } loop @@ -193,7 +193,8 @@ impl Parser for LangParser { // Rule callback - let (new_cursor, reports) = (*rule).on_match(self, &doc, rule_pos, match_data); + let dd: &'a dyn Document = unsafe {std::mem::transmute(&doc as &dyn Document)}; + let (new_cursor, reports) = rule.on_match(self, dd, rule_pos, match_data); self.handle_reports(doc.source(), reports); @@ -210,10 +211,10 @@ impl Parser for LangParser self.handle_reports(doc.source(), self.state_mut().on_scope_end(self, &doc, super::state::Scope::DOCUMENT)); - return doc; + return Box::new(doc); } - fn parse_into<'a>(&self, source: Rc, document: &'a Document<'a>) + fn parse_into<'a>(&self, source: Rc, document: &'a dyn Document<'a>) { let mut matches = Vec::new(); for _ in 0..self.rules.len() { @@ -228,10 +229,10 @@ impl Parser for LangParser let (rule_pos, rule, match_data) = self.update_matches(&cursor, &mut matches); // Unmatched content - let text_content = util::process_text(&document, &content.as_str()[cursor.pos..rule_pos.pos]); + let text_content = util::process_text(document, &content.as_str()[cursor.pos..rule_pos.pos]); if !text_content.is_empty() { - self.push(&document, Box::new(Text::new( + self.push(document, Box::new(Text::new( Token::new(cursor.pos..rule_pos.pos, source.clone()), text_content ))); @@ -240,7 +241,7 @@ impl Parser for LangParser if let Some(rule) = rule { // Rule callback - let (new_cursor, reports) = (*rule).on_match(self, &document, rule_pos, match_data); + let (new_cursor, reports) = (*rule).on_match(self, document, rule_pos, match_data); self.handle_reports(document.source(), reports); diff --git a/src/parser/parser.rs b/src/parser/parser.rs index aab0ba3..be104a1 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -115,11 +115,11 @@ pub trait Parser: KernelHolder } /// Add an [`Element`] to the [`Document`] - fn push<'a>(&self, doc: &'a Document<'a>, elem: Box); + fn push<'a>(&self, doc: &dyn Document, elem: Box); /// Parse [`Source`] into a new [`Document`] - fn parse<'a>(&self, source: Rc, parent: Option<&'a Document<'a>>) -> Document<'a>; + fn parse<'a>(&self, source: Rc, parent: Option<&'a dyn Document<'a>>) -> Box+'a>; /// Parse [`Source`] into an already existing [`Document`] - fn parse_into<'a>(&self, source: Rc, document: &'a Document<'a>); + fn parse_into<'a>(&self, source: Rc, document: &'a dyn Document<'a>); } diff --git a/src/parser/rule.rs b/src/parser/rule.rs index c344800..99c7706 100644 --- a/src/parser/rule.rs +++ b/src/parser/rule.rs @@ -14,7 +14,7 @@ pub trait Rule { /// Finds the next match starting from [`cursor`] fn next_match(&self, cursor: &Cursor) -> Option<(usize, Box)>; /// Callback when rule matches - fn on_match(&self, parser: &dyn Parser, document: &Document, cursor: Cursor, match_data: Option>) -> (Cursor, Vec, Range)>>); + fn on_match<'a>(&self, parser: &dyn Parser, document: &'a (dyn Document<'a>+'a), cursor: Cursor, match_data: Option>) -> (Cursor, Vec, Range)>>); /// Export bindings to lua fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)>; } @@ -73,7 +73,7 @@ pub trait RegexRule fn regexes(&self) -> &[regex::Regex]; /// Callback on regex rule match - fn on_regex_match(&self, index: usize, parser: &dyn Parser, document: &Document, token: Token, matches: regex::Captures) -> Vec, Range)>>; + fn on_regex_match<'a>(&self, index: usize, parser: &dyn Parser, document: &'a (dyn Document<'a>+'a), token: Token, matches: regex::Captures) -> Vec, Range)>>; fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)>; } @@ -100,7 +100,7 @@ impl Rule for T { (pos, Box::new(id) as Box)); } - fn on_match(&self, parser: &dyn Parser, document: &Document, cursor: Cursor, match_data: Option>) + fn on_match<'a>(&self, parser: &dyn Parser, document: &'a (dyn Document<'a>+'a), cursor: Cursor, match_data: Option>) -> (Cursor, Vec, Range)>>) { let content = cursor.source.content(); let index = unsafe { match_data.unwrap_unchecked().downcast::().unwrap_unchecked() }; diff --git a/src/parser/state.rs b/src/parser/state.rs index 2ec01f9..5cc9cee 100644 --- a/src/parser/state.rs +++ b/src/parser/state.rs @@ -27,7 +27,7 @@ pub trait State: Downcast fn scope(&self) -> Scope; /// Callback called when state goes out of scope - fn on_remove<'a>(&self, parser: &dyn Parser, document: &Document) -> Vec, Range)>>; + fn on_remove<'a>(&self, parser: &dyn Parser, document: &dyn Document) -> Vec, Range)>>; } impl_downcast!(State); @@ -70,7 +70,7 @@ impl StateHolder .map_or(None, |st| Some(st.clone())) } - pub fn on_scope_end(&mut self, parser: &dyn Parser, document: &Document, scope: Scope) -> Vec, Range)>> + pub fn on_scope_end(&mut self, parser: &dyn Parser, document: &dyn Document, scope: Scope) -> Vec, Range)>> { let mut result = vec![]; diff --git a/src/parser/util.rs b/src/parser/util.rs index 6e5c09f..219ef37 100644 --- a/src/parser/util.rs +++ b/src/parser/util.rs @@ -2,10 +2,10 @@ use std::collections::HashMap; use unicode_segmentation::UnicodeSegmentation; -use crate::{document::{document::Document, element::ElemKind}, elements::paragraph::Paragraph}; +use crate::{document::{document::{Document, DocumentAccessors}, element::ElemKind}, elements::paragraph::Paragraph}; /// Processes text for escape characters and paragraphing -pub fn process_text(document: &Document, content: &str) -> String +pub fn process_text(document: &dyn Document, content: &str) -> String { let mut escaped = false; let mut newlines = 0usize; // Consecutive newlines @@ -30,7 +30,7 @@ pub fn process_text(document: &Document, content: &str) -> String } } None => { - if document.last_element::(false) + if document.last_element::() .and_then(|par| par.find_back(|e| e.kind() != ElemKind::Invisible) .and_then(|e| Some(e.kind() == ElemKind::Inline))) .unwrap_or(false) @@ -65,7 +65,7 @@ pub fn process_text(document: &Document, content: &str) -> String // Content begins with whitespace if prev.is_none() { - if document.last_element::(false).is_some() + if document.last_element::().is_some() { return (out+g, Some(g)); }