ftml/parsing/rule/impls/block/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
/*
* parsing/rule/impls/block/mod.rs
*
* ftml - Library to parse Wikidot text
* Copyright (C) 2019-2025 Wikijump Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! Meta-rule for all block constructs.
//!
//! This matches `[[` or `[[*` and runs the block parsing
//! against the upcoming tokens in accordance to how the
//! various blocks define themselves.
use crate::parsing::result::ParseResult;
use crate::parsing::rule::{LineRequirement, Rule};
use crate::parsing::Parser;
use crate::tree::Elements;
use std::fmt::{self, Debug};
mod arguments;
mod mapping;
mod parser;
mod rule;
pub mod blocks;
pub use self::arguments::Arguments;
pub use self::rule::{RULE_BLOCK, RULE_BLOCK_SKIP_NEWLINE, RULE_BLOCK_STAR};
/// Define a rule for how to parse a block.
#[derive(Clone)]
pub struct BlockRule {
/// The code name of the block.
///
/// As this is an internal structure, we can assert the following things:
/// * It is in kebab-case.
/// * It is globally unique.
/// * It is prefixed with `block-`.
name: &'static str,
/// Which names you can use this block with. Case-insensitive.
/// Will panic if empty.
accepts_names: &'static [&'static str],
/// Whether this block accepts the star flag (`*`).
///
/// For instance, user can be invoked as both
/// `[[user aismallard]]` and `[[*user aismallard]]`.
accepts_star: bool,
/// Whether this block accepts the score flag (`_`).
///
/// For instance, div can be invoked as both
/// `[[div]]` and `[[div_]]`.
accepts_score: bool,
/// Whether this block optionally allows its head and tail to be separated by newlines.
/// These newlines will be consumed and not be interpreted as line breaks.
///
/// For instance, `[[div]]`, which can be declared on separate lines, or inline, without
/// those newlines becoming part of the resultant element:
///
/// ```text
/// [[div]]
/// My fancy div!
/// [[/div]]
/// ```
///
/// ```text
/// [[div]]My fancy inline div![[/div]]
/// ```
accepts_newlines: bool,
/// Function which implements the processing for this rule.
parse_fn: BlockParseFn,
}
impl BlockRule {
/// Produces a pseudo parse `Rule` associated with this `BlockRule`.
///
/// It should not be invoked, it is for error construction.
#[cold]
pub fn rule(&self) -> Rule {
// Stubbed try_consume_fn implementation for the Rule.
fn try_consume_fn<'r, 't>(
_: &mut Parser<'r, 't>,
) -> ParseResult<'r, 't, Elements<'t>> {
panic!("Pseudo rule for this block should not be executed directly!");
}
Rule {
name: self.name,
position: LineRequirement::Any,
try_consume_fn,
}
}
}
impl Debug for BlockRule {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BlockRule")
.field("name", &self.name)
.field("accepts_names", &self.accepts_names)
.field("accepts_star", &self.accepts_star)
.field("accepts_score", &self.accepts_score)
.field("accepts_newlines", &self.accepts_newlines)
.field("parse_fn", &(self.parse_fn as *const ()))
.finish()
}
}
/// Function pointer type to implement block parsing.
///
/// The arguments are, in order:
/// * `parser` -- `Parser` instance
/// * `name` -- The name of the block
/// * `flag_star` -- Whether this block is has the star flag (`*`).
/// * `flag_score` -- Whether this block has the score flag (`_`).
/// * `in_head` -- Whether we're still in the block head, or if it's finished
pub type BlockParseFn = for<'r, 't> fn(
&mut Parser<'r, 't>,
&'t str,
bool,
bool,
bool,
) -> ParseResult<'r, 't, Elements<'t>>;