From 104e1021776728e9662d0923b8bf1b095e561e35 Mon Sep 17 00:00:00 2001 From: ef3d0c3e Date: Wed, 24 Jul 2024 13:20:29 +0200 Subject: [PATCH] Format --- src/cache/cache.rs | 83 ++++------ src/document/document.rs | 219 +++++++++++++------------- src/elements/graphviz.rs | 9 +- src/elements/link.rs | 229 +++++++++++++++------------- src/elements/list.rs | 2 +- src/elements/raw.rs | 312 +++++++++++++++++++++++--------------- src/elements/registrar.rs | 30 ++-- src/elements/script.rs | 295 ++++++++++++++++++++--------------- src/elements/text.rs | 100 +++++++----- 9 files changed, 709 insertions(+), 570 deletions(-) diff --git a/src/cache/cache.rs b/src/cache/cache.rs index 650422d..bbe90ed 100644 --- a/src/cache/cache.rs +++ b/src/cache/cache.rs @@ -1,29 +1,13 @@ -use std::{error::Error, path::PathBuf}; +use rusqlite::types::FromSql; +use rusqlite::Connection; +use rusqlite::ToSql; -use rusqlite::{types::FromSql, Connection, Params, ToSql}; - -struct Cache { - con: Connection -} - -impl Cache { - fn new(file: PathBuf) -> Result { - match Connection::open(file) - { - Err(e) => return Err(format!("Could not connect to cache database: {}", e.to_string())), - Ok(con) => Ok(Self { con }) - } - } -} - -pub enum CachedError -{ +pub enum CachedError { SqlErr(rusqlite::Error), - GenErr(E) + GenErr(E), } -pub trait Cached -{ +pub trait Cached { type Key; type Value; @@ -39,10 +23,8 @@ pub trait Cached fn key(&self) -> ::Key; - fn init(con: &mut Connection) -> Result<(), rusqlite::Error> - { - con.execute(::sql_table(), ()) - .map(|_| ()) + fn init(con: &mut Connection) -> Result<(), rusqlite::Error> { + con.execute(::sql_table(), ()).map(|_| ()) } /// Attempts to retrieve a cached element from the compilation database @@ -54,53 +36,50 @@ pub trait Cached /// or if not cached, an error from the generator [`f`] /// /// Note that on error, [`f`] may still have been called - fn cached(&self, con: &mut Connection, f: F) - -> Result<::Value, CachedError> + fn cached( + &self, + con: &mut Connection, + f: F, + ) -> Result<::Value, CachedError> where ::Key: ToSql, ::Value: FromSql + ToSql, F: FnOnce(&Self) -> Result<::Value, E>, - { + { let key = self.key(); // Find in cache - let mut query = match con.prepare(::sql_get_query()) - { + let mut query = match con.prepare(::sql_get_query()) { Ok(query) => query, - Err(e) => return Err(CachedError::SqlErr(e)) + Err(e) => return Err(CachedError::SqlErr(e)), }; - let value = query.query_row([&key], |row| - { - Ok(row.get_unwrap::<_, ::Value>(0)) - }).ok(); + let value = query + .query_row([&key], |row| { + Ok(row.get_unwrap::<_, ::Value>(0)) + }) + .ok(); - if let Some(value) = value - { + if let Some(value) = value { // Found in cache - return Ok(value) - } - else - { + return Ok(value); + } else { // Compute a value - let value = match f(&self) - { + let value = match f(&self) { Ok(val) => val, - Err(e) => return Err(CachedError::GenErr(e)) + Err(e) => return Err(CachedError::GenErr(e)), }; // Try to insert - let mut query = match con.prepare(::sql_insert_query()) - { + let mut query = match con.prepare(::sql_insert_query()) { Ok(query) => query, - Err(e) => return Err(CachedError::SqlErr(e)) + Err(e) => return Err(CachedError::SqlErr(e)), }; - match query.execute((&key, &value)) - { + match query.execute((&key, &value)) { Ok(_) => Ok(value), - Err(e) => Err(CachedError::SqlErr(e)) + Err(e) => Err(CachedError::SqlErr(e)), } } - } + } } diff --git a/src/document/document.rs b/src/document/document.rs index 9f5886e..60282a1 100644 --- a/src/document/document.rs +++ b/src/document/document.rs @@ -1,4 +1,6 @@ -use std::cell::{Ref, RefCell, RefMut}; +use std::cell::Ref; +use std::cell::RefCell; +use std::cell::RefMut; use std::collections::hash_map::HashMap; use std::rc::Rc; @@ -7,14 +9,13 @@ use crate::parser::source::Source; 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 + /// List of all referenceable elements in current scope. + /// All elements in this should return a non empty pub referenceable: HashMap, pub variables: HashMap>, } @@ -27,38 +28,43 @@ impl Scope { } } - pub fn merge(&mut self, other: &mut Scope, merge_as: &String, ref_offset: usize) - { - match merge_as.is_empty() - { - true => { - // References - self.referenceable.extend(other.referenceable.drain() - .map(|(name, idx)| - (name, idx+ref_offset))); + pub fn merge(&mut self, other: &mut Scope, merge_as: &String, ref_offset: usize) { + match merge_as.is_empty() { + true => { + // References + self.referenceable.extend( + other + .referenceable + .drain() + .map(|(name, idx)| (name, idx + ref_offset)), + ); - // Variables - self.variables.extend(other.variables.drain() - .map(|(name, var)| - (name, var))); - }, - false => { - // References - self.referenceable.extend(other.referenceable.drain() - .map(|(name, idx)| - (format!("{merge_as}.{name}"), idx+ref_offset))); + // Variables + self.variables + .extend(other.variables.drain().map(|(name, var)| (name, var))); + } + false => { + // References + self.referenceable.extend( + other + .referenceable + .drain() + .map(|(name, idx)| (format!("{merge_as}.{name}"), idx + ref_offset)), + ); - // Variables - self.variables.extend(other.variables.drain() - .map(|(name, var)| - (format!("{merge_as}.{name}"), var))); - } - } - } + // Variables + self.variables.extend( + other + .variables + .drain() + .map(|(name, var)| (format!("{merge_as}.{name}"), var)), + ); + } + } + } } -pub trait Document<'a>: core::fmt::Debug -{ +pub trait Document<'a>: core::fmt::Debug { /// Gets the document [`Source`] fn source(&self) -> Rc; @@ -73,16 +79,12 @@ pub trait Document<'a>: core::fmt::Debug fn scope(&self) -> &RefCell; /// Pushes a new element into the document's content - fn push(&self, elem: Box) - { + fn push(&self, elem: Box) { // TODO: RefTable - self.content() - .borrow_mut() - .push(elem); + self.content().borrow_mut().push(elem); } - /* fn last_element(&'a self, recurse: bool) -> Option> { @@ -116,88 +118,89 @@ pub trait Document<'a>: core::fmt::Debug } */ - fn add_variable(&self, variable: Rc) - { - self.scope().borrow_mut().variables.insert( - variable.name().to_string(), - variable); - } - - fn get_variable(&self, name: &str) -> Option> - { - match self.scope().borrow().variables.get(name) - { - Some(variable) => { - return Some(variable.clone()); - }, - - // Continue search recursively - None => match self.parent() { - Some(parent) => return parent.get_variable(name), - - // Not found - None => return None, - } - } - } - - fn remove_variable(&self, name: &str) -> Option> - { - match self.scope().borrow_mut().variables.remove(name) - { - Some(variable) => { - return Some(variable.clone()); - }, - - // Continue search recursively - None => match self.parent() { - Some(parent) => return parent.remove_variable(name), - - // Not found - None => return None, - } - } + fn add_variable(&self, variable: Rc) { + self.scope() + .borrow_mut() + .variables + .insert(variable.name().to_string(), variable); } - /// Merges [`other`] into [`self`] - fn merge(&self, content: &RefCell>>, scope: &RefCell, merge_as: Option<&String>) - { - match merge_as + fn get_variable(&self, name: &str) -> Option> { + match self.scope().borrow().variables.get(name) { + Some(variable) => { + return Some(variable.clone()); + } + + // Continue search recursively + None => match self.parent() { + Some(parent) => return parent.get_variable(name), + + // Not found + None => return None, + }, + } + } + + /* + fn remove_variable(&self, name: &str) -> Option> + { + match self.scope().borrow_mut().variables.remove(name) { - Some(merge_as) => self.scope().borrow_mut() - .merge( - &mut *scope.borrow_mut(), - merge_as, - self.content().borrow().len()+1), - _ => {}, + Some(variable) => { + return Some(variable.clone()); + }, + + // Continue search recursively + None => match self.parent() { + Some(parent) => return parent.remove_variable(name), + + // Not found + None => return None, + } + } + } + */ + + /// Merges [`other`] into [`self`] + fn merge( + &self, + content: &RefCell>>, + scope: &RefCell, + merge_as: Option<&String>, + ) { + match merge_as { + Some(merge_as) => self.scope().borrow_mut().merge( + &mut *scope.borrow_mut(), + merge_as, + self.content().borrow().len() + 1, + ), + _ => {} } - // Content - self.content().borrow_mut().extend((content.borrow_mut()) - .drain(..) - .map(|value| value)); - } + // Content + self.content() + .borrow_mut() + .extend((content.borrow_mut()).drain(..).map(|value| value)); + } } -pub trait DocumentAccessors<'a> -{ +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() +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() + 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/elements/graphviz.rs b/src/elements/graphviz.rs index 7431d25..9ecb080 100644 --- a/src/elements/graphviz.rs +++ b/src/elements/graphviz.rs @@ -1,11 +1,6 @@ use std::collections::HashMap; -use std::io::Read; -use std::io::Write; use std::ops::Range; -use std::process::Command; -use std::process::Stdio; use std::rc::Rc; -use std::str::FromStr; use std::sync::Once; use crate::parser::util::Property; @@ -19,10 +14,7 @@ use crypto::digest::Digest; use crypto::sha2::Sha512; use graphviz_rust::cmd::Format; use graphviz_rust::cmd::Layout; -use graphviz_rust::exec; use graphviz_rust::exec_dot; -use graphviz_rust::parse; -use graphviz_rust::printer::PrinterContext; use mlua::Function; use mlua::Lua; use regex::Captures; @@ -129,6 +121,7 @@ impl Element for Graphviz { } } }); + // TODO: Format svg in a div if let Some(mut con) = compiler.cache() { match self.cached(&mut con, |s| s.dot_to_svg()) { diff --git a/src/elements/link.rs b/src/elements/link.rs index 24b1188..3e79f0e 100644 --- a/src/elements/link.rs +++ b/src/elements/link.rs @@ -1,48 +1,60 @@ -use mlua::{Function, Lua}; -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}; -use crate::{compiler::compiler::{Compiler, Target}, document::{document::Document, element::{ElemKind, Element}}}; -use std::{ops::Range, rc::Rc}; +use crate::compiler::compiler::Compiler; +use crate::compiler::compiler::Target; +use crate::document::document::Document; +use crate::document::element::ElemKind; +use crate::document::element::Element; +use crate::parser::parser::Parser; +use crate::parser::rule::RegexRule; +use crate::parser::source::Source; +use crate::parser::source::Token; +use crate::parser::util; +use ariadne::Fmt; +use ariadne::Label; +use ariadne::Report; +use ariadne::ReportKind; +use mlua::Function; +use mlua::Lua; +use regex::Captures; +use regex::Regex; +use std::ops::Range; +use std::rc::Rc; #[derive(Debug)] pub struct Link { - location: Token, + location: Token, name: String, // Link name - url: String, // Link url + url: String, // Link url } -impl Link -{ - pub fn new(location: Token, name: String, url: String) -> Self { - Self { location: location, name, url } - } +impl Link { + pub fn new(location: Token, name: String, url: String) -> Self { + Self { + location: location, + name, + url, + } + } } -impl Element for Link -{ - fn location(&self) -> &Token { &self.location } - 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: &dyn Document) -> Result { - match compiler.target() - { - Target::HTML => { - Ok(format!("{}", - compiler.sanitize(self.url.as_str()), - compiler.sanitize(self.name.as_str()), - )) - }, - Target::LATEX => { - Ok(format!("\\href{{{}}}{{{}}}", - compiler.sanitize(self.url.as_str()), - compiler.sanitize(self.name.as_str()), - )) - }, - } - } +impl Element for Link { + fn location(&self) -> &Token { &self.location } + 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: &dyn Document) -> Result { + match compiler.target() { + Target::HTML => Ok(format!( + "{}", + compiler.sanitize(self.url.as_str()), + compiler.sanitize(self.name.as_str()), + )), + Target::LATEX => Ok(format!( + "\\href{{{}}}{{{}}}", + compiler.sanitize(self.url.as_str()), + compiler.sanitize(self.name.as_str()), + )), + } + } } pub struct LinkRule { @@ -51,7 +63,9 @@ pub struct LinkRule { impl LinkRule { pub fn new() -> Self { - Self { re: [Regex::new(r"\[((?:\\.|[^\\\\])*?)\]\(((?:\\.|[^\\\\])*?)\)").unwrap()] } + Self { + re: [Regex::new(r"\[((?:\\.|[^\\\\])*?)\]\(((?:\\.|[^\\\\])*?)\)").unwrap()], + } } } @@ -60,93 +74,100 @@ impl RegexRule for LinkRule { fn regexes(&self) -> &[Regex] { &self.re } - fn on_regex_match<'a>(&self, _: usize, parser: &dyn Parser, document: &'a dyn Document, token: Token, matches: 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) - { - Some(name) => { - if name.as_str().is_empty() - { + let link_name = match matches.get(1) { + Some(name) => { + if name.as_str().is_empty() { result.push( Report::build(ReportKind::Error, token.source(), name.start()) - .with_message("Empty link name") - .with_label( - Label::new((token.source().clone(), name.range())) - .with_message("Link name is empty") - .with_color(parser.colors().error)) - .finish()); + .with_message("Empty link name") + .with_label( + Label::new((token.source().clone(), name.range())) + .with_message("Link name is empty") + .with_color(parser.colors().error), + ) + .finish(), + ); return result; - } + } // TODO: process into separate document... - let text_content = util::process_text(document, name.as_str()); + let text_content = util::process_text(document, name.as_str()); - if text_content.as_str().is_empty() - { + if text_content.as_str().is_empty() { result.push( Report::build(ReportKind::Error, token.source(), name.start()) - .with_message("Empty link name") - .with_label( - Label::new((token.source(), name.range())) - .with_message(format!("Link name is empty. Once processed, `{}` yields `{}`", - name.as_str().fg(parser.colors().highlight), - text_content.as_str().fg(parser.colors().highlight), - )) - .with_color(parser.colors().error)) - .finish()); + .with_message("Empty link name") + .with_label( + Label::new((token.source(), name.range())) + .with_message(format!( + "Link name is empty. Once processed, `{}` yields `{}`", + name.as_str().fg(parser.colors().highlight), + text_content.as_str().fg(parser.colors().highlight), + )) + .with_color(parser.colors().error), + ) + .finish(), + ); return result; - } + } text_content - }, - _ => panic!("Empty link name"), - }; + } + _ => panic!("Empty link name"), + }; - let link_url = match matches.get(2) - { - Some(url) => { - if url.as_str().is_empty() - { + let link_url = match matches.get(2) { + Some(url) => { + if url.as_str().is_empty() { result.push( Report::build(ReportKind::Error, token.source(), url.start()) - .with_message("Empty link url") - .with_label( - Label::new((token.source(), url.range())) - .with_message("Link url is empty") - .with_color(parser.colors().error)) - .finish()); + .with_message("Empty link url") + .with_label( + Label::new((token.source(), url.range())) + .with_message("Link url is empty") + .with_color(parser.colors().error), + ) + .finish(), + ); return result; - } - let text_content = util::process_text(document, url.as_str()); + } + let text_content = util::process_text(document, url.as_str()); - if text_content.as_str().is_empty() - { + if text_content.as_str().is_empty() { result.push( Report::build(ReportKind::Error, token.source(), url.start()) - .with_message("Empty link url") - .with_label( - Label::new((token.source(), url.range())) - .with_message(format!("Link url is empty. Once processed, `{}` yields `{}`", - url.as_str().fg(parser.colors().highlight), - text_content.as_str().fg(parser.colors().highlight), - )) - .with_color(parser.colors().error)) - .finish()); + .with_message("Empty link url") + .with_label( + Label::new((token.source(), url.range())) + .with_message(format!( + "Link url is empty. Once processed, `{}` yields `{}`", + url.as_str().fg(parser.colors().highlight), + text_content.as_str().fg(parser.colors().highlight), + )) + .with_color(parser.colors().error), + ) + .finish(), + ); return result; - } + } text_content - }, - _ => panic!("Empty link url"), - }; + } + _ => panic!("Empty link url"), + }; - parser.push(document, Box::new( - Link::new( - token.clone(), - link_name, - link_url - ) - )); + parser.push( + document, + Box::new(Link::new(token.clone(), link_name, link_url)), + ); - return result; + return result; } // TODO diff --git a/src/elements/list.rs b/src/elements/list.rs index a73b7ae..e6e093f 100644 --- a/src/elements/list.rs +++ b/src/elements/list.rs @@ -95,7 +95,7 @@ impl Element for List match_stack(&mut result, &ent.numbering); result.push_str("
  • "); match ent.content.iter().enumerate() - .try_for_each(|(idx, elem)| { + .try_for_each(|(_idx, elem)| { match elem.compile(compiler, document) { Err(e) => Err(e), Ok(s) => { result.push_str(s.as_str()); Ok(()) } diff --git a/src/elements/raw.rs b/src/elements/raw.rs index 0b01d36..a1b0309 100644 --- a/src/elements/raw.rs +++ b/src/elements/raw.rs @@ -1,8 +1,30 @@ -use mlua::{Error::BadArgument, Function, Lua}; -use regex::{Captures, Regex}; -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, PropertyMapError, PropertyParser}}}; -use ariadne::{Fmt, Label, Report, ReportKind}; -use std::{collections::HashMap, ops::Range, rc::Rc, str::FromStr, sync::Arc}; +use crate::compiler::compiler::Compiler; +use crate::document::document::Document; +use crate::document::element::ElemKind; +use crate::document::element::Element; +use crate::lua::kernel::CTX; +use crate::parser::parser::Parser; +use crate::parser::rule::RegexRule; +use crate::parser::source::Source; +use crate::parser::source::Token; +use crate::parser::util::Property; +use crate::parser::util::PropertyMapError; +use crate::parser::util::PropertyParser; +use crate::parser::util::{self}; +use ariadne::Fmt; +use ariadne::Label; +use ariadne::Report; +use ariadne::ReportKind; +use mlua::Error::BadArgument; +use mlua::Function; +use mlua::Lua; +use regex::Captures; +use regex::Regex; +use std::collections::HashMap; +use std::ops::Range; +use std::rc::Rc; +use std::str::FromStr; +use std::sync::Arc; #[derive(Debug)] struct Raw { @@ -12,22 +34,26 @@ struct Raw { } impl Raw { - fn new(location: Token, kind: ElemKind, content: String) -> Self { - Self { location, kind, content } - } + fn new(location: Token, kind: ElemKind, content: String) -> Self { + Self { + location, + kind, + content, + } + } } impl Element for Raw { - fn location(&self) -> &Token { &self.location } - fn kind(&self) -> ElemKind { self.kind.clone() } + fn location(&self) -> &Token { &self.location } + fn kind(&self) -> ElemKind { self.kind.clone() } - fn element_name(&self) -> &'static str { "Raw" } + fn element_name(&self) -> &'static str { "Raw" } - fn to_string(&self) -> String { format!("{self:#?}") } + fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result { + fn compile(&self, _compiler: &Compiler, _document: &dyn Document) -> Result { Ok(self.content.clone()) - } + } } pub struct RawRule { @@ -38,172 +64,212 @@ pub struct RawRule { impl RawRule { pub fn new() -> Self { let mut props = HashMap::new(); - props.insert("kind".to_string(), + props.insert( + "kind".to_string(), Property::new( true, "Element display kind".to_string(), - Some("inline".to_string()))); + Some("inline".to_string()), + ), + ); Self { - re: [ - Regex::new(r"\{\?(?:\[((?:\\.|[^\[\]\\])*?)\])?(?:((?:\\.|[^\\\\])*?)(\?\}))?").unwrap() + re: [ + Regex::new(r"\{\?(?:\[((?:\\.|[^\[\]\\])*?)\])?(?:((?:\\.|[^\\\\])*?)(\?\}))?") + .unwrap(), ], - properties: PropertyParser::new(props) - } + properties: PropertyParser::new(props), + } } } -impl RegexRule for RawRule -{ - fn name(&self) -> &'static str { "Raw" } +impl RegexRule for RawRule { + fn name(&self) -> &'static str { "Raw" } - fn regexes(&self) -> &[regex::Regex] { &self.re } + fn regexes(&self) -> &[regex::Regex] { &self.re } - fn on_regex_match(&self, _index: usize, parser: &dyn Parser, document: &dyn 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 mut reports = vec![]; - let raw_content = match matches.get(2) - { + let raw_content = match matches.get(2) { // Unterminated None => { reports.push( Report::build(ReportKind::Error, token.source(), token.start()) - .with_message("Unterminated Raw Code") - .with_label( - Label::new((token.source().clone(), token.range.clone())) - .with_message(format!("Missing terminating `{}` after first `{}`", - "?}".fg(parser.colors().info), - "{?".fg(parser.colors().info))) - .with_color(parser.colors().error)) - .finish()); - return reports; + .with_message("Unterminated Raw Code") + .with_label( + Label::new((token.source().clone(), token.range.clone())) + .with_message(format!( + "Missing terminating `{}` after first `{}`", + "?}".fg(parser.colors().info), + "{?".fg(parser.colors().info) + )) + .with_color(parser.colors().error), + ) + .finish(), + ); + return reports; } Some(content) => { - let processed = util::process_escaped('\\', "?}", - content.as_str().trim_start().trim_end()); + let processed = + util::process_escaped('\\', "?}", content.as_str().trim_start().trim_end()); - if processed.is_empty() - { + if processed.is_empty() { reports.push( Report::build(ReportKind::Warning, token.source(), content.start()) - .with_message("Empty Raw Code") - .with_label( - Label::new((token.source().clone(), content.range())) - .with_message("Raw code is empty") - .with_color(parser.colors().warning)) - .finish()); + .with_message("Empty Raw Code") + .with_label( + Label::new((token.source().clone(), content.range())) + .with_message("Raw code is empty") + .with_color(parser.colors().warning), + ) + .finish(), + ); } processed } }; - let properties = match matches.get(1) - { + let properties = match matches.get(1) { None => match self.properties.default() { Ok(properties) => properties, Err(e) => { reports.push( Report::build(ReportKind::Error, token.source(), token.start()) - .with_message("Invalid Raw Code") - .with_label( - Label::new((token.source().clone(), token.range.clone())) - .with_message(format!("Raw code is missing properties: {e}")) - .with_color(parser.colors().error)) - .finish()); - return reports; - }, - } + .with_message("Invalid Raw Code") + .with_label( + Label::new((token.source().clone(), token.range.clone())) + .with_message(format!("Raw code is missing properties: {e}")) + .with_color(parser.colors().error), + ) + .finish(), + ); + return reports; + } + }, Some(props) => { - let processed = util::process_escaped('\\', "]", - props.as_str().trim_start().trim_end()); - match self.properties.parse(processed.as_str()) - { + let processed = + util::process_escaped('\\', "]", props.as_str().trim_start().trim_end()); + match self.properties.parse(processed.as_str()) { Err(e) => { reports.push( Report::build(ReportKind::Error, token.source(), props.start()) - .with_message("Invalid Raw Code Properties") - .with_label( - Label::new((token.source().clone(), props.range())) - .with_message(e) - .with_color(parser.colors().error)) - .finish()); + .with_message("Invalid Raw Code Properties") + .with_label( + Label::new((token.source().clone(), props.range())) + .with_message(e) + .with_color(parser.colors().error), + ) + .finish(), + ); return reports; } - Ok(properties) => properties + Ok(properties) => properties, } } }; - let raw_kind : ElemKind = match properties.get("kind", - |prop, value| ElemKind::from_str(value.as_str()).map_err(|e| (prop, e))) - { + let raw_kind: ElemKind = match properties.get("kind", |prop, value| { + ElemKind::from_str(value.as_str()).map_err(|e| (prop, e)) + }) { Ok((_prop, kind)) => kind, Err(e) => match e { PropertyMapError::ParseError((prop, err)) => { reports.push( Report::build(ReportKind::Error, token.source(), token.start()) - .with_message("Invalid Raw Code Property") - .with_label( - Label::new((token.source().clone(), token.range.clone())) - .with_message(format!("Property `kind: {}` cannot be converted: {}", - prop.fg(parser.colors().info), - err.fg(parser.colors().error))) - .with_color(parser.colors().warning)) - .finish()); - return reports; - }, + .with_message("Invalid Raw Code Property") + .with_label( + Label::new((token.source().clone(), token.range.clone())) + .with_message(format!( + "Property `kind: {}` cannot be converted: {}", + prop.fg(parser.colors().info), + err.fg(parser.colors().error) + )) + .with_color(parser.colors().warning), + ) + .finish(), + ); + return reports; + } PropertyMapError::NotFoundError(err) => { reports.push( Report::build(ReportKind::Error, token.source(), token.start()) - .with_message("Invalid Code Property") - .with_label( - Label::new((token.source().clone(), token.start()+1..token.end())) - .with_message(format!("Property `{}` is missing", - err.fg(parser.colors().info))) - .with_color(parser.colors().warning)) - .finish()); - return reports; + .with_message("Invalid Code Property") + .with_label( + Label::new(( + token.source().clone(), + token.start() + 1..token.end(), + )) + .with_message(format!( + "Property `{}` is missing", + err.fg(parser.colors().info) + )) + .with_color(parser.colors().warning), + ) + .finish(), + ); + return reports; } - } + }, }; - parser.push(document, Box::new(Raw { - location: token.clone(), - kind: raw_kind, - content: raw_content - })); + parser.push( + document, + Box::new(Raw { + location: token.clone(), + kind: raw_kind, + content: raw_content, + }), + ); - reports - } + reports + } - fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { + 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}")))}) - }; + 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, - })); - })); + 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(), + )); - Ok(()) - }).unwrap())); - bindings - } + } } diff --git a/src/elements/registrar.rs b/src/elements/registrar.rs index ec69c42..379bbf9 100644 --- a/src/elements/registrar.rs +++ b/src/elements/registrar.rs @@ -17,20 +17,20 @@ use super::variable::VariableRule; use super::variable::VariableSubstitutionRule; pub fn register(parser: &mut P) { - parser.add_rule(Box::new(CommentRule::new()), None); - parser.add_rule(Box::new(ParagraphRule::new()), None); - parser.add_rule(Box::new(ImportRule::new()), None); - parser.add_rule(Box::new(ScriptRule::new()), None); - parser.add_rule(Box::new(VariableRule::new()), None); - parser.add_rule(Box::new(VariableSubstitutionRule::new()), None); - parser.add_rule(Box::new(RawRule::new()), None); - parser.add_rule(Box::new(ListRule::new()), None); - parser.add_rule(Box::new(CodeRule::new()), None); - parser.add_rule(Box::new(TexRule::new()), None); - parser.add_rule(Box::new(GraphRule::new()), None); + parser.add_rule(Box::new(CommentRule::new()), None).unwrap(); + parser.add_rule(Box::new(ParagraphRule::new()), None).unwrap(); + parser.add_rule(Box::new(ImportRule::new()), None).unwrap(); + parser.add_rule(Box::new(ScriptRule::new()), None).unwrap(); + parser.add_rule(Box::new(VariableRule::new()), None).unwrap(); + parser.add_rule(Box::new(VariableSubstitutionRule::new()), None).unwrap(); + parser.add_rule(Box::new(RawRule::new()), None).unwrap(); + parser.add_rule(Box::new(ListRule::new()), None).unwrap(); + parser.add_rule(Box::new(CodeRule::new()), None).unwrap(); + parser.add_rule(Box::new(TexRule::new()), None).unwrap(); + parser.add_rule(Box::new(GraphRule::new()), None).unwrap(); - parser.add_rule(Box::new(StyleRule::new()), None); - parser.add_rule(Box::new(SectionRule::new()), None); - parser.add_rule(Box::new(LinkRule::new()), None); - parser.add_rule(Box::new(TextRule::default()), None); + parser.add_rule(Box::new(StyleRule::new()), None).unwrap(); + parser.add_rule(Box::new(SectionRule::new()), None).unwrap(); + parser.add_rule(Box::new(LinkRule::new()), None).unwrap(); + parser.add_rule(Box::new(TextRule::default()), None).unwrap(); } diff --git a/src/elements/script.rs b/src/elements/script.rs index fa083ff..eec6359 100644 --- a/src/elements/script.rs +++ b/src/elements/script.rs @@ -1,211 +1,262 @@ -use mlua::{Function, Lua}; -use regex::{Captures, Regex}; -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 std::{ops::Range, rc::Rc}; +use crate::document::document::Document; +use crate::lua::kernel::Kernel; +use crate::lua::kernel::KernelContext; +use crate::parser::parser::Parser; +use crate::parser::parser::ReportColors; +use crate::parser::rule::RegexRule; +use crate::parser::source::Source; +use crate::parser::source::Token; +use crate::parser::source::VirtualSource; +use crate::parser::util; +use ariadne::Fmt; +use ariadne::Label; +use ariadne::Report; +use ariadne::ReportKind; +use mlua::Function; +use mlua::Lua; +use regex::Captures; +use regex::Regex; +use std::ops::Range; +use std::rc::Rc; use super::text::Text; -pub struct ScriptRule -{ +pub struct ScriptRule { re: [Regex; 2], - eval_kinds: [(&'static str, &'static str); 3] + eval_kinds: [(&'static str, &'static str); 3], } impl ScriptRule { pub fn new() -> Self { Self { - re: [ + 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"), ("\"", "Eval to text"), ("!", "Eval and parse"), - ] - } + ], + } } - fn validate_kernel_name(colors: &ReportColors, name: &str) - -> Result { + fn validate_kernel_name(colors: &ReportColors, name: &str) -> Result { let trimmed = name.trim_end().trim_start(); - if trimmed.is_empty() { return Ok("main".to_string()) } - else if trimmed.find(|c: char| c.is_whitespace()).is_some() { - return Err(format!("Kernel name `{}` contains whitespaces", - trimmed.fg(colors.highlight))) + if trimmed.is_empty() { + return Ok("main".to_string()); + } else if trimmed.find(|c: char| c.is_whitespace()).is_some() { + return Err(format!( + "Kernel name `{}` contains whitespaces", + trimmed.fg(colors.highlight) + )); } Ok(trimmed.to_string()) } - fn validate_kind(&self, colors: &ReportColors, kind: &str) - -> Result { - match self.eval_kinds.iter().position(|(kind_symbol, _)| kind == *kind_symbol) + fn validate_kind(&self, colors: &ReportColors, kind: &str) -> Result { + match self + .eval_kinds + .iter() + .position(|(kind_symbol, _)| kind == *kind_symbol) { Some(id) => Ok(id), - None => Err(format!("Unable to find eval kind `{}`. Available kinds:{}", - kind.fg(colors.highlight), - self.eval_kinds.iter().fold(String::new(), |out, (symbol, name)| { + None => Err(format!( + "Unable to find eval kind `{}`. Available kinds:{}", + kind.fg(colors.highlight), + self.eval_kinds + .iter() + .fold(String::new(), |out, (symbol, name)| { out + format!("\n - '{symbol}' => {name}").as_str() - }))) + }) + )), } } } -impl RegexRule for ScriptRule -{ - fn name(&self) -> &'static str { "Script" } +impl RegexRule for ScriptRule { + fn name(&self) -> &'static str { "Script" } - fn regexes(&self) -> &[regex::Regex] { &self.re } + fn regexes(&self) -> &[regex::Regex] { &self.re } - fn on_regex_match<'a>(&self, index: usize, parser: &dyn Parser, document: &'a dyn Document<'a>, token: Token, matches: Captures) - -> Vec, Range)>> { + 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(1) { None => "main".to_string(), - Some(name) => { - match ScriptRule::validate_kernel_name(parser.colors(), name.as_str()) - { - Ok(name) => name, - Err(e) => { - reports.push( - Report::build(ReportKind::Error, token.source(), name.start()) + Some(name) => match ScriptRule::validate_kernel_name(parser.colors(), name.as_str()) { + Ok(name) => name, + Err(e) => { + reports.push( + Report::build(ReportKind::Error, token.source(), name.start()) .with_message("Invalid kernel name") .with_label( Label::new((token.source(), name.range())) - .with_message(e) - .with_color(parser.colors().error)) - .finish()); - return reports; - } + .with_message(e) + .with_color(parser.colors().error), + ) + .finish(), + ); + return reports; } - } + }, }; - let kernel = parser.get_kernel(kernel_name.as_str()).unwrap_or_else(|| { - parser.insert_kernel(kernel_name.to_string(), Kernel::new(parser)) - }); + let kernel = parser + .get_kernel(kernel_name.as_str()) + .unwrap_or_else(|| parser.insert_kernel(kernel_name.to_string(), Kernel::new(parser))); - let kernel_data = matches.get(if index == 0 {2} else {3}) - .and_then(|code| { + let kernel_data = matches + .get(if index == 0 { 2 } else { 3 }) + .and_then(|code| { let trimmed = code.as_str().trim_start().trim_end(); (!trimmed.is_empty()).then_some((trimmed, code.range())) - }).or_else(|| { + }) + .or_else(|| { reports.push( Report::build(ReportKind::Warning, token.source(), token.start()) - .with_message("Invalid kernel code") - .with_label( - Label::new((token.source(), token.start()+1..token.end())) - .with_message("Kernel code is empty") - .with_color(parser.colors().warning)) - .finish()); + .with_message("Invalid kernel code") + .with_label( + Label::new((token.source(), token.start() + 1..token.end())) + .with_message("Kernel code is empty") + .with_color(parser.colors().warning), + ) + .finish(), + ); None }); - if kernel_data.is_none() { return reports; } + if kernel_data.is_none() { + return reports; + } let (kernel_content, kernel_range) = kernel_data.unwrap(); let source = Rc::new(VirtualSource::new( Token::new(kernel_range, token.source()), - format!("{}#{}:lua_kernel@{kernel_name}", token.source().name(), matches.get(0).unwrap().start()), - util::process_escaped('\\', ">@", kernel_content) + format!( + "{}#{}:lua_kernel@{kernel_name}", + token.source().name(), + matches.get(0).unwrap().start() + ), + util::process_escaped('\\', ">@", kernel_content), )) as Rc; - let execute = |lua: &Lua| - { - let chunk = lua.load(source.content()) - .set_name(kernel_name); + let execute = |lua: &Lua| { + let chunk = lua.load(source.content()).set_name(kernel_name); - if index == 0 // Exec + if index == 0 + // Exec { - if let Err(e) = chunk.exec() - { + if let Err(e) = chunk.exec() { reports.push( Report::build(ReportKind::Error, source.clone(), 0) - .with_message("Invalid kernel code") - .with_label( - Label::new((source.clone(), 0..source.content().len())) - .with_message(format!("Kernel execution failed:\n{}", e.to_string())) - .with_color(parser.colors().error)) - .finish()); + .with_message("Invalid kernel code") + .with_label( + Label::new((source.clone(), 0..source.content().len())) + .with_message(format!( + "Kernel execution failed:\n{}", + e.to_string() + )) + .with_color(parser.colors().error), + ) + .finish(), + ); return reports; } - } - else // Eval + } else + // Eval { // Validate kind let kind = match matches.get(2) { None => 0, - Some(kind) => { - match self.validate_kind(parser.colors(), kind.as_str()) - { - Ok(kind) => kind, - Err(msg) => { - reports.push( - Report::build(ReportKind::Error, token.source(), kind.start()) + Some(kind) => match self.validate_kind(parser.colors(), kind.as_str()) { + Ok(kind) => kind, + Err(msg) => { + reports.push( + Report::build(ReportKind::Error, token.source(), kind.start()) .with_message("Invalid kernel code kind") .with_label( Label::new((token.source(), kind.range())) - .with_message(msg) - .with_color(parser.colors().error)) - .finish()); - return reports; - } + .with_message(msg) + .with_color(parser.colors().error), + ) + .finish(), + ); + return reports; } - } + }, }; - - if kind == 0 // Eval + + if kind == 0 + // Eval { - if let Err(e) = chunk.eval::<()>() - { + if let Err(e) = chunk.eval::<()>() { reports.push( Report::build(ReportKind::Error, source.clone(), 0) - .with_message("Invalid kernel code") - .with_label( - Label::new((source.clone(), 0..source.content().len())) - .with_message(format!("Kernel evaluation failed:\n{}", e.to_string())) - .with_color(parser.colors().error)) - .finish()); + .with_message("Invalid kernel code") + .with_label( + Label::new((source.clone(), 0..source.content().len())) + .with_message(format!( + "Kernel evaluation failed:\n{}", + e.to_string() + )) + .with_color(parser.colors().error), + ) + .finish(), + ); } - } - else // Eval to string + } else + // Eval to string { - match chunk.eval::() - { + match chunk.eval::() { Ok(result) => { - if kind == 1 // Eval to text + if kind == 1 + // Eval to text { - if !result.is_empty() - { - parser.push(document, Box::new(Text::new( - Token::new(1..source.content().len(), source.clone()), - util::process_text(document, result.as_str()), - ))); + if !result.is_empty() { + parser.push( + document, + Box::new(Text::new( + Token::new(1..source.content().len(), source.clone()), + util::process_text(document, result.as_str()), + )), + ); } - } - else if kind == 2 // Eval and Parse + } else if kind == 2 + // Eval and Parse { let parse_source = Rc::new(VirtualSource::new( - Token::new(0..source.content().len(), source.clone()), - format!("parse({})", source.name()), - result + Token::new(0..source.content().len(), source.clone()), + format!("parse({})", source.name()), + result, )) as Rc; parser.parse_into(parse_source, document); } - }, + } Err(e) => { reports.push( Report::build(ReportKind::Error, source.clone(), 0) - .with_message("Invalid kernel code") - .with_label( - Label::new((source.clone(), 0..source.content().len())) - .with_message(format!("Kernel evaluation failed:\n{}", e.to_string())) - .with_color(parser.colors().error)) - .finish()); + .with_message("Invalid kernel code") + .with_label( + Label::new((source.clone(), 0..source.content().len())) + .with_message(format!( + "Kernel evaluation failed:\n{}", + e.to_string() + )) + .with_color(parser.colors().error), + ) + .finish(), + ); } } } @@ -217,11 +268,11 @@ impl RegexRule for ScriptRule let ctx = KernelContext { location: Token::new(0..source.content().len(), source.clone()), parser, - document + document, }; kernel.run_with_context(ctx, execute) - } + } // TODO fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } diff --git a/src/elements/text.rs b/src/elements/text.rs index ea765d5..2f4f04a 100644 --- a/src/elements/text.rs +++ b/src/elements/text.rs @@ -1,62 +1,88 @@ -use mlua::{Function, Lua}; +use std::any::Any; +use std::ops::Range; +use std::rc::Rc; -use crate::{compiler::compiler::Compiler, document::{document::Document, element::{ElemKind, Element}}, lua::kernel::CTX, parser::{parser::Parser, rule::Rule, source::Token}}; +use ariadne::Report; +use mlua::Function; +use mlua::Lua; + +use crate::compiler::compiler::Compiler; +use crate::document::document::Document; +use crate::document::element::ElemKind; +use crate::document::element::Element; +use crate::lua::kernel::CTX; +use crate::parser::parser::Parser; +use crate::parser::rule::Rule; +use crate::parser::source::Cursor; +use crate::parser::source::Source; +use crate::parser::source::Token; #[derive(Debug)] -pub struct Text -{ - pub(self) location: Token, +pub struct Text { + pub(self) location: Token, pub(self) content: String, } -impl Text -{ - pub fn new(location: Token, content: String) -> Text - { +impl Text { + pub fn new(location: Token, content: String) -> Text { Text { - location: location, - content: content + location: location, + content: content, } } } -impl Element for Text -{ - fn location(&self) -> &Token { &self.location } - fn kind(&self) -> ElemKind { ElemKind::Inline } +impl Element for Text { + fn location(&self) -> &Token { &self.location } + fn kind(&self) -> ElemKind { ElemKind::Inline } fn element_name(&self) -> &'static str { "Text" } - fn to_string(&self) -> String { format!("{self:#?}") } + fn to_string(&self) -> String { format!("{self:#?}") } - fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result { - Ok(compiler.sanitize(self.content.as_str())) - } + fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result { + Ok(compiler.sanitize(self.content.as_str())) + } } #[derive(Default)] pub struct TextRule; -impl Rule for TextRule -{ - fn name(&self) -> &'static str { "Text" } +impl Rule for TextRule { + fn name(&self) -> &'static str { "Text" } - fn next_match(&self, cursor: &crate::parser::source::Cursor) -> Option<(usize, Box)> { None } + fn next_match(&self, _cursor: &Cursor) -> Option<(usize, Box)> { None } - 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 on_match( + &self, + _parser: &dyn Parser, + _document: &dyn Document, + _cursor: Cursor, + _match_data: Option>, + ) -> (Cursor, Vec, Range)>>) { + panic!("Text cannot match"); + } - fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { + 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| { - ctx.parser.push(ctx.document, Box::new(Text { - location: ctx.location.clone(), - content, - })); - })); + bindings.push(( + "push".to_string(), + lua.create_function(|_, content: String| { + CTX.with_borrow(|ctx| { + ctx.as_ref().map(|ctx| { + ctx.parser.push( + ctx.document, + Box::new(Text { + location: ctx.location.clone(), + content, + }), + ); + }) + }); + + Ok(()) + }) + .unwrap(), + )); - Ok(()) - }).unwrap())); - bindings - } + } }