libhanzzok/syntax/parse/
parse_decorator_chain.rs1use nom::{
2 branch::alt,
3 combinator::{map, not, opt, recognize},
4 multi::{many0, many1},
5 sequence::{preceded, terminated, tuple},
6};
7
8use crate::{
9 core::ast::{DecoratorChainNode, DecoratorNode, InlineObjectNode, TextNode},
10 syntax::{Token, TokenKind},
11};
12
13use super::{
14 nom_ext::{satisfy, satisfy_transform, skip_any_spaces, tag, HanzzokParser},
15 parse_hzdata::parse_hzdata_paired,
16 parse_inline_constructor::parse_inline_constructor,
17 parse_text::{parse_escaped_text, parse_fallback_text},
18 ParseResult,
19};
20
21fn parse_decorator_params(p: HanzzokParser) -> ParseResult<Vec<Token>> {
22 parse_hzdata_paired(
23 TokenKind::PunctuationLeftParenthesis,
24 TokenKind::PunctuationRightParenthesis,
25 true,
26 )(p)
27}
28
29pub fn parse_decorator_chain(p: HanzzokParser) -> ParseResult<DecoratorChainNode> {
30 let tt = p.create_tracker();
31
32 let (p, _) = tag(TokenKind::PunctuationLeftSquareBracket)(p)?;
33
34 let (p, _) = skip_any_spaces(p)?;
35
36 let (p, main_text) = alt((
37 map(
38 parse_inline_constructor,
39 InlineObjectNode::InlineConstructor,
40 ),
41 map(
42 many1(alt((
43 parse_escaped_text,
44 preceded(
45 not(alt((
46 recognize(tuple((
47 tag(TokenKind::PunctuationFullStop),
48 satisfy(|t| matches!(t.kind, TokenKind::Word(_))),
49 ))),
50 recognize(tag(TokenKind::PunctuationRightSquareBracket)),
51 ))),
52 parse_fallback_text,
53 ),
54 ))),
55 |nodes| {
56 InlineObjectNode::Text(TextNode {
57 tokens: nodes
58 .into_iter()
59 .flat_map(|node| node.tokens.into_iter())
60 .collect(),
61 })
62 },
63 ),
64 ))(p)?;
65
66 let (p, _) = skip_any_spaces(p)?;
67
68 let (p, decorators) = many0(terminated(
69 |p: HanzzokParser| {
70 let tt = p.create_tracker();
71 let (p, _) = tag(TokenKind::PunctuationFullStop)(p)?;
72 let (p, name) = many1(satisfy_transform(|t| match &t.kind {
73 TokenKind::Word(w) => Some(w.clone()),
74 TokenKind::PunctuationHyphenMinus => Some("-".to_owned()),
75 _ => None,
76 }))(p)?;
77 let (p, params) = opt(parse_decorator_params)(p)?;
78 let tokens = tt.end(&p);
79 Ok((
80 p,
81 DecoratorNode {
82 tokens,
83 name: name.into_iter().map(|(_, name)| name).collect(),
84 params: params
85 .map(|params| params.into_iter().map(|t| t.text).collect::<String>()),
86 },
87 ))
88 },
89 skip_any_spaces,
90 ))(p)?;
91
92 let (p, _) = tag(TokenKind::PunctuationRightSquareBracket)(p)?;
93
94 let tokens = tt.end(&p);
95
96 Ok((
97 p,
98 DecoratorChainNode {
99 main_text: Box::new(main_text),
100 decorators,
101 tokens,
102 },
103 ))
104}