org_rust_parser/object/
inline_src.rs1use crate::constants::{LBRACE, LBRACK, NEWLINE, RBRACE, RBRACK};
2use crate::node_pool::NodeID;
3use crate::types::{Cursor, MatchError, ParseOpts, Parseable, Parser, Result};
4use crate::utils::Match;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct InlineSrc<'a> {
8 pub lang: &'a str,
9 pub headers: Option<&'a str>,
10 pub body: &'a str,
11}
12
13impl<'a> Parseable<'a> for InlineSrc<'a> {
14 fn parse(
15 parser: &mut Parser<'a>,
16 mut cursor: Cursor<'a>,
17 parent: Option<NodeID>,
18 parse_opts: ParseOpts,
19 ) -> Result<NodeID> {
20 let start = cursor.index;
21 cursor.word("src_")?;
22
23 let lang =
24 cursor.fn_until(|chr: u8| chr == b'[' || chr == b'{' || chr.is_ascii_whitespace())?;
25
26 cursor.index = lang.end;
27
28 match cursor.curr() {
29 LBRACE => {
30 let body = Self::parse_body(cursor)?;
31 Ok(parser.alloc(
32 Self {
33 lang: lang.obj,
34 headers: None,
35 body: body.obj,
36 },
37 start,
38 body.end,
39 None,
40 ))
41 }
42 LBRACK => {
43 let header = Self::parse_header(cursor)?;
44 cursor.move_to(header.end);
45 if cursor.curr() == LBRACE {
46 let body = Self::parse_body(cursor)?;
47 Ok(parser.alloc(
48 Self {
49 lang: lang.obj,
50 headers: Some(header.obj),
51 body: body.obj,
52 },
53 start,
54 body.end,
55 parent,
56 ))
57 } else {
58 Err(MatchError::InvalidLogic)
59 }
60 }
61 _ => Err(MatchError::InvalidLogic),
64 }
65 }
66}
67
68impl<'a> InlineSrc<'a> {
69 fn parse_header(cursor: Cursor) -> Result<Match<&str>> {
71 InlineSrc::parse_src(cursor, LBRACK, RBRACK)
72 }
73 fn parse_body(cursor: Cursor) -> Result<Match<&str>> {
74 InlineSrc::parse_src(cursor, LBRACE, RBRACE)
75 }
76 #[inline(always)]
77 fn parse_src(mut cursor: Cursor, lperim: u8, rperim: u8) -> Result<Match<&str>> {
78 let mut bracket_count: i32 = 0;
82
83 let start = cursor.index;
84 loop {
85 match cursor.curr() {
86 chr if chr == lperim => {
87 bracket_count -= 1;
88 }
89 chr if chr == rperim => {
90 bracket_count += 1;
91 if bracket_count == 0 {
92 return Ok(Match {
93 start,
94 end: cursor.index + 1,
96 obj: cursor.clamp_backwards(start + 1),
97 });
98 }
99 }
100 NEWLINE => {
101 return Err(MatchError::InvalidLogic);
102 }
103 _ => {}
104 } cursor.next();
107 } }
109}
110
111#[cfg(test)]
112mod tests {
113 use crate::expr_in_pool;
114 use crate::object::InlineSrc;
115 use crate::parse_org;
116 use crate::types::Expr;
117 use pretty_assertions::assert_eq;
118
119 #[test]
120 fn basic_src() {
121 let input = "src_python{neat}";
122
123 let parsed = parse_org(input);
124 let l = expr_in_pool!(parsed, InlineSrc).unwrap();
125
126 assert_eq!(
127 l,
128 &InlineSrc {
129 lang: "python",
130 headers: None,
131 body: "neat"
132 }
133 )
134 }
135
136 #[test]
137 fn inlinesrc_header() {
138 let input = "src_python[fun]{rad}";
139
140 let parsed = parse_org(input);
141 let l = expr_in_pool!(parsed, InlineSrc).unwrap();
142
143 assert_eq!(
144 l,
145 &InlineSrc {
146 lang: "python",
147 headers: Some("fun"),
148 body: "rad"
149 }
150 )
151 }
152}