From 9592a8ffba35d8c2b516dfcf965a6915051ba65c Mon Sep 17 00:00:00 2001 From: Artemy Egorov Date: Mon, 12 Aug 2024 11:33:10 +0300 Subject: [PATCH] feat: daleth parser --- src/daleth/format.rs | 4 +- src/daleth/lexer/mod.rs | 2 +- src/daleth/lexer/types.rs | 4 +- src/daleth/parser/mod.rs | 135 ++++++++++++++++++++++++++++++++++++-- src/traits/from_daletl.rs | 10 --- src/traits/to_daletl.rs | 10 --- src/typed.rs | 7 -- 7 files changed, 134 insertions(+), 38 deletions(-) diff --git a/src/daleth/format.rs b/src/daleth/format.rs index bd81691..975773e 100644 --- a/src/daleth/format.rs +++ b/src/daleth/format.rs @@ -40,7 +40,7 @@ fn additional_str<'src>( Token::TextBody(_) => "", Token::MLText(_) => "", Token::MLMSText(_, _) => "", - Token::RMLText(_) => "", + Token::MLRText(_) => "", _ => "\n", }; @@ -100,7 +100,7 @@ pub fn format<'src>(spanned_tokens: &Vec>>) -> String { set_indent(t, current_indent + 1), prepend_indent("}", current_indent) ), - Token::RMLText(t) => format!(" {{#{t}}}\n"), + Token::MLRText(t) => format!(" {{#{t}}}\n"), Token::Comment(c) => format!("{}\n", prepend_indent(&format!("#{c}"), current_indent)), Token::TextTag(t) => format!("{}\n", prepend_indent(t, current_indent)), diff --git a/src/daleth/lexer/mod.rs b/src/daleth/lexer/mod.rs index 9d9e49e..88f0e68 100644 --- a/src/daleth/lexer/mod.rs +++ b/src/daleth/lexer/mod.rs @@ -159,7 +159,7 @@ fn textual<'src>() -> impl Parser<'src, &'src str, Token<'src>, extra::Err { MLText(&'src str), /// Multi Line with min spaces text MLMSText(usize, &'src str), - /// Raw Multi line text - RMLText(&'src str), + /// Multi Line raw text + MLRText(&'src str), // Special TextTag(&'src str), diff --git a/src/daleth/parser/mod.rs b/src/daleth/parser/mod.rs index e3d8eee..8a72661 100644 --- a/src/daleth/parser/mod.rs +++ b/src/daleth/parser/mod.rs @@ -3,8 +3,9 @@ pub mod types; use super::{ lexer::types::Token, types::{Span, Spanned}, + utils::{set_indent, trim_indent}, }; -use crate::typed::{Page, Tag::*}; +use crate::typed::{AlignArg, Body, Hl, NNArg, NNBody, Page, TNullArg, Tag::*}; use chumsky::prelude::*; use types::*; @@ -14,11 +15,133 @@ pub fn parser<'tokens, 'src: 'tokens>() -> impl Parser< Spanned, extra::Err, Span>>, > { - let br = just(Token::Br).to(Br); + recursive(|tag| { + let tags_body = tag + .clone() + .repeated() + .collect() + .delimited_by(just(Token::LSquare), just(Token::RSquare)); - let tag = br; + let text_body = select! { + Token::TextBody(t) => t.to_owned(), + Token::MLText(t) => trim_indent(t).to_owned(), + Token::MLMSText(n, t) => set_indent(t, n).to_owned(), + Token::MLRText(t) => t.to_owned() + }; - tag.repeated() - .collect() - .map_with(|t, e| (Page { data: t }, e.span())) + let nnbody = text_body + .map(NNBody::Text) + .or(tags_body.clone().map(NNBody::Tags)); + + let body = text_body + .map(Body::Text) + .or(tags_body.clone().map(Body::Tags)) + .or_not() + .to(Body::Null); + + let num_arg = select! { + Token::NumberArgument(n) => n + }; + + let text_arg = select! { + Token::TextArgument(t) => t.to_owned() + }; + + let nnarg = text_arg.map(NNArg::Text).or(num_arg.map(NNArg::Number)); + let tnullarg = text_arg + .map(TNullArg::Text) + .or_not() + .map(|v| v.unwrap_or(TNullArg::Null)); + let hlarg = num_arg.try_map(|n, s| Hl::try_from(n).map_err(|e| Rich::custom(s, e))); + let alignarg = + num_arg.try_map(|n, s| AlignArg::try_from(n).map_err(|e| Rich::custom(s, e))); + + let el = just(Token::El).ignore_then(nnbody.clone()).map(El); + let h = just(Token::H) + .ignore_then(hlarg) + .then(text_body) + .map(|(level, body)| H(body, level)); + let p = just(Token::P).ignore_then(nnbody.clone()).map(P); + let br = just(Token::Br).to(Br); + let ul = just(Token::Ul).ignore_then(tags_body.clone()).map(Ul); + let ol = just(Token::Ol).ignore_then(tags_body.clone()).map(Ol); + let row = just(Token::Row) + .ignore_then(alignarg.or_not()) + .then(tags_body.clone()) + .map(|(arg, body)| Row(body, arg.unwrap_or(AlignArg::Start))); + let link = just(Token::Link) + .ignore_then(text_arg.clone()) + .then(body.clone()) + .map(|(arg, body)| Link(body, arg)); + let navlink = just(Token::Navlink) + .ignore_then(text_arg.clone()) + .then(body.clone()) + .map(|(arg, body)| Navlink(body, arg)); + let btn = just(Token::Btn) + .ignore_then(text_arg.clone()) + .then(body.clone()) + .map(|(arg, body)| Btn(body, arg)); + let navbtn = just(Token::Navbtn) + .ignore_then(text_arg.clone()) + .then(body.clone()) + .map(|(arg, body)| Navbtn(body, arg)); + let img = just(Token::Img).ignore_then(text_arg.clone()).map(Img); + let table = just(Token::Table).ignore_then(tags_body.clone()).map(Table); + let tcol = just(Token::Tcol).ignore_then(tags_body.clone()).map(Tcol); + let tpcol = just(Token::Tpcol).ignore_then(tags_body.clone()).map(Tpcol); + let hr = just(Token::Hr).to(Hr); + let b = just(Token::B).ignore_then(text_body.clone()).map(B); + let i = just(Token::I).ignore_then(text_body.clone()).map(I); + let bq = just(Token::Bq).ignore_then(nnbody.clone()).map(Bq); + let footlnk = just(Token::Footlnk).ignore_then(nnarg).map(Footlnk); + let footn = just(Token::Footn) + .ignore_then(nnarg.clone()) + .then(text_body.clone()) + .map(|(arg, body)| Footn(body, arg)); + let a = just(Token::A).ignore_then(nnarg.clone()).map(A); + let s = just(Token::S).ignore_then(text_body.clone()).map(S); + let sup = just(Token::Sup).ignore_then(text_body.clone()).map(Sup); + let sub = just(Token::Sub).ignore_then(text_body.clone()).map(Sub); + let disc = just(Token::Disc).ignore_then(nnbody.clone()).map(Disc); + let block = just(Token::Block) + .ignore_then(alignarg.or_not()) + .then(nnbody.clone()) + .map(|(arg, body)| Block(body, arg.unwrap_or(AlignArg::Start))); + let carousel = just(Token::Carousel) + .ignore_then(tags_body.clone()) + .map(Carousel); + let code = just(Token::Code) + .ignore_then(tnullarg) + .then(text_body.clone()) + .map(|(arg, body)| Code(body, arg)); + let pre = just(Token::Pre).ignore_then(text_body.clone()).map(Pre); + let meta = just(Token::Meta) + .ignore_then(text_arg) + .then(text_body.clone()) + .map(|(arg, body)| Meta(body, arg)); + + let el_text = select! { + Token::TextTag(t) => El(NNBody::Text(t.to_owned())) + }; + + let el_tags = tag + .repeated() + .collect() + .delimited_by(just(Token::ElOpen), just(Token::ElClose)) + .map(|v| El(NNBody::Tags(v))); + + let paragraph = select! { + Token::Paragraph(t) => P(NNBody::Text(t.replace("\n"," ").trim().to_owned())) + }; + + choice(( + el, h, p, br, ul, ol, row, link, navlink, btn, navbtn, img, table, tcol, tpcol, hr, b, + i, bq, footlnk, footn, a, s, sup, sub, disc, + )) + .or(choice((block, carousel, code, pre, meta))) + .or(choice((el_text, el_tags, paragraph))) + }) + .repeated() + .collect() + .map_with(|t, e| (Page { data: t }, e.span())) } diff --git a/src/traits/from_daletl.rs b/src/traits/from_daletl.rs index 26c27f5..ee93ebe 100644 --- a/src/traits/from_daletl.rs +++ b/src/traits/from_daletl.rs @@ -109,16 +109,6 @@ impl TryFrom for String { } } -impl From for Arg { - fn from(value: DlArgument) -> Self { - match value { - DlArgument::Text(s) => s.into(), - DlArgument::Number(n) => n.into(), - DlArgument::Null => Self::Null, - } - } -} - impl TryFrom for NNArg { type Error = ConversionError; diff --git a/src/traits/to_daletl.rs b/src/traits/to_daletl.rs index c33bcb9..00f2b90 100644 --- a/src/traits/to_daletl.rs +++ b/src/traits/to_daletl.rs @@ -83,16 +83,6 @@ impl From for DlBody { } } -impl From for DlArgument { - fn from(item: Arg) -> DlArgument { - match item { - Arg::Null => NA, - Arg::Number(v) => v.into(), - Arg::Text(v) => v.into(), - } - } -} - impl From for DlArgument { fn from(item: NNArg) -> DlArgument { match item { diff --git a/src/typed.rs b/src/typed.rs index b949378..b099d22 100644 --- a/src/typed.rs +++ b/src/typed.rs @@ -65,13 +65,6 @@ pub enum NNBody { /// Text body pub type TBody = String; -#[derive(AutoFrom, Debug, Clone, PartialEq, Eq)] -pub enum Arg { - Text(String), - Number(u8), - Null, -} - #[derive(AutoFrom, Debug, Clone, PartialEq, Eq)] pub enum TNullArg { Text(String),