busbar_sf_agentscript/parser/
primitives.rs1use crate::ast::Spanned;
7use crate::lexer::Token;
8use chumsky::input::MappedInput;
9use chumsky::prelude::*;
10
11pub type Span = SimpleSpan<usize>;
13
14pub type SpannedToken<'src> = (Token<'src>, Span);
16
17pub type ParserInput<'tokens, 'src> =
20 MappedInput<'tokens, Token<'src>, Span, &'tokens [SpannedToken<'src>]>;
21
22pub fn to_ast_span(span: Span) -> std::ops::Range<usize> {
24 span.start..span.end
25}
26
27pub fn ident<'tokens, 'src: 'tokens>() -> impl Parser<
29 'tokens,
30 ParserInput<'tokens, 'src>,
31 &'src str,
32 extra::Err<Rich<'tokens, Token<'src>, Span>>,
33> + Clone {
34 select! {
35 Token::Ident(s) => s,
36 }
37}
38
39pub fn spanned_ident<'tokens, 'src: 'tokens>() -> impl Parser<
41 'tokens,
42 ParserInput<'tokens, 'src>,
43 Spanned<String>,
44 extra::Err<Rich<'tokens, Token<'src>, Span>>,
45> + Clone {
46 ident().map_with(|s, e| Spanned::new(s.to_string(), to_ast_span(e.span())))
47}
48
49pub fn string_lit<'tokens, 'src: 'tokens>() -> impl Parser<
51 'tokens,
52 ParserInput<'tokens, 'src>,
53 &'src str,
54 extra::Err<Rich<'tokens, Token<'src>, Span>>,
55> + Clone {
56 select! {
57 Token::StringLit(s) => s,
58 }
59}
60
61pub fn spanned_string<'tokens, 'src: 'tokens>() -> impl Parser<
63 'tokens,
64 ParserInput<'tokens, 'src>,
65 Spanned<String>,
66 extra::Err<Rich<'tokens, Token<'src>, Span>>,
67> + Clone {
68 string_lit().map_with(|s, e| Spanned::new(s.to_string(), to_ast_span(e.span())))
69}
70
71pub fn number_lit<'tokens, 'src: 'tokens>() -> impl Parser<
73 'tokens,
74 ParserInput<'tokens, 'src>,
75 f64,
76 extra::Err<Rich<'tokens, Token<'src>, Span>>,
77> + Clone {
78 select! {
79 Token::NumberLit(n) => n,
80 }
81}
82
83pub fn newline<'tokens, 'src: 'tokens>(
85) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
86 + Clone {
87 just(Token::Newline).ignored()
88}
89
90#[allow(dead_code)]
92pub fn skip_newlines<'tokens, 'src: 'tokens>(
93) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
94 + Clone {
95 newline().repeated().ignored()
96}
97
98pub fn indent<'tokens, 'src: 'tokens>(
100) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
101 + Clone {
102 just(Token::Indent).ignored()
103}
104
105pub fn dedent<'tokens, 'src: 'tokens>(
107) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
108 + Clone {
109 just(Token::Dedent).ignored()
110}
111
112#[allow(dead_code)]
114pub fn skip_noise<'tokens, 'src: 'tokens>(
115) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
116 + Clone {
117 choice((newline(), indent(), dedent(), select! { Token::Comment(_) => () }))
118 .repeated()
119 .ignored()
120}
121
122pub fn skip_block_noise<'tokens, 'src: 'tokens>(
124) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
125 + Clone {
126 choice((newline(), select! { Token::Comment(_) => () }))
127 .repeated()
128 .ignored()
129}
130
131pub fn skip_toplevel_noise<'tokens, 'src: 'tokens>(
134) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
135 + Clone {
136 choice((newline(), dedent(), select! { Token::Comment(_) => () }))
137 .repeated()
138 .ignored()
139}
140
141#[allow(dead_code)]
143pub fn skip_comments<'tokens, 'src: 'tokens>(
144) -> impl Parser<'tokens, ParserInput<'tokens, 'src>, (), extra::Err<Rich<'tokens, Token<'src>, Span>>>
145 + Clone {
146 select! { Token::Comment(_) => () }.repeated().ignored()
147}
148
149pub fn description_entry<'tokens, 'src: 'tokens>() -> impl Parser<
151 'tokens,
152 ParserInput<'tokens, 'src>,
153 Spanned<String>,
154 extra::Err<Rich<'tokens, Token<'src>, Span>>,
155> + Clone {
156 just(Token::Description)
157 .ignore_then(just(Token::Colon))
158 .ignore_then(spanned_string())
159}