Skip to content

Commit 9efaff4

Browse files
committed
feat: Support for any and all functions in expr parser
1 parent 38ff66a commit 9efaff4

1 file changed

Lines changed: 116 additions & 25 deletions

File tree

galileo/src/expr/parser.rs

Lines changed: 116 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ fn func0(func_name: &str, constructor: Expr, args: Vec<Expr>) -> Result<Expr, St
5858
struct FuncContext<'src> {
5959
func_name: &'src str,
6060
func_name_span: SimpleSpan,
61-
args: Vec<Option<(Expr, &'src str, SimpleSpan)>>,
61+
args: Vec<Option<(FuncArgument, &'src str, SimpleSpan)>>,
6262
}
6363

6464
impl<'src> FuncContext<'src> {
6565
fn new(
6666
func_name: &'src str,
6767
func_name_span: SimpleSpan,
68-
args: Vec<(Expr, &'src str, SimpleSpan)>,
68+
args: Vec<(FuncArgument, &'src str, SimpleSpan)>,
6969
) -> Self {
7070
Self {
7171
func_name,
@@ -108,45 +108,103 @@ impl<'src> FuncContext<'src> {
108108
format!("Unknown function `{}`", self.func_name),
109109
))
110110
}
111-
}
112111

113-
trait GetArg<'src, T> {
114-
fn get(&mut self, index: usize) -> Result<T, Rich<'src, char>>;
115-
}
116-
117-
impl<'src> GetArg<'src, String> for FuncContext<'src> {
118-
fn get(&mut self, index: usize) -> Result<String, Rich<'src, char>> {
112+
fn get_arg(
113+
&mut self,
114+
index: usize,
115+
) -> Result<(FuncArgument, &'src str, SimpleSpan), Rich<'src, char>> {
119116
if index >= self.args.len() {
120117
return Err(Rich::custom(
121118
self.func_name_span,
122119
format!("function {} missing argumnt {}", self.func_name, index + 1),
123120
));
124121
}
125122

126-
let arg = self.args[index]
123+
Ok(self.args[index]
127124
.take()
128-
.expect("arguments are used only once");
125+
.expect("arguments are used only once"))
126+
}
127+
128+
fn arg_type_err(
129+
&self,
130+
src: &'src str,
131+
span: SimpleSpan,
132+
arg_index: usize,
133+
expected: &'static str,
134+
) -> Rich<'src, char> {
135+
Rich::custom(
136+
span,
137+
format!(
138+
"expected `{expected}` argument at position `{}` of function `{}`, but got `{src}`",
139+
arg_index + 1,
140+
self.func_name,
141+
),
142+
)
143+
}
144+
}
129145

130-
if let Expr::Literal(ExprValue::String(value)) = arg.0 {
146+
trait GetArg<'src, T> {
147+
fn get(&mut self, index: usize) -> Result<T, Rich<'src, char>>;
148+
}
149+
150+
impl<'src> GetArg<'src, String> for FuncContext<'src> {
151+
fn get(&mut self, index: usize) -> Result<String, Rich<'src, char>> {
152+
let arg = self.get_arg(index)?;
153+
if let FuncArgument::Expression(Expr::Literal(ExprValue::String(value))) = arg.0 {
131154
Ok(value)
132155
} else {
133-
Err(Rich::custom(
134-
arg.2,
135-
format!(
136-
"expected `String` argument at position `{}` of function `{}`, but got `{}`",
137-
index + 1,
138-
self.func_name,
139-
arg.1,
140-
),
141-
))
156+
Err(self.arg_type_err(arg.1, arg.2, index, "String"))
142157
}
143158
}
144159
}
145160

161+
impl<'src> GetArg<'src, Vec<Expr>> for FuncContext<'src> {
162+
fn get(&mut self, index: usize) -> Result<Vec<Expr>, Rich<'src, char>> {
163+
let arg = self.get_arg(index)?;
164+
if let FuncArgument::Array(arr) = arg.0 {
165+
Ok(arr)
166+
} else {
167+
dbg!(&arg.0);
168+
Err(self.arg_type_err(arg.1, arg.2, index, "[Array]"))
169+
}
170+
}
171+
}
172+
173+
#[derive(Debug)]
174+
enum FuncArgument {
175+
Expression(Expr),
176+
Array(Vec<Expr>),
177+
Tuple(Vec<Expr>),
178+
}
179+
180+
fn func_arg<'src>(
181+
expr_parser: impl Parser<'src, &'src str, Expr, Error<'src>> + Clone + 'src,
182+
) -> impl Parser<'src, &'src str, FuncArgument, Error<'src>> {
183+
let expr = expr_parser.clone().map(FuncArgument::Expression);
184+
185+
let array = expr_parser
186+
.clone()
187+
.separated_by(just(','))
188+
.allow_trailing()
189+
.collect::<Vec<_>>()
190+
.delimited_by(just('['), just(']'))
191+
.map(FuncArgument::Array);
192+
193+
let tuple = expr_parser
194+
.separated_by(just(','))
195+
.at_least(2)
196+
.allow_trailing()
197+
.collect::<Vec<_>>()
198+
.delimited_by(just('('), just(')'))
199+
.map(FuncArgument::Tuple);
200+
201+
choice((array, tuple, expr)).padded()
202+
}
203+
146204
fn func_call<'src>(
147205
expr_parser: impl Parser<'src, &'src str, Expr, Error<'src>> + Clone + 'src,
148206
) -> impl Parser<'src, &'src str, Expr, Error<'src>> {
149-
let arg_list = expr_parser
207+
let arg_list = func_arg(expr_parser)
150208
.map_with(|expr, e| (expr, e.slice(), e.span()))
151209
.separated_by(just(','))
152210
.allow_trailing()
@@ -156,9 +214,12 @@ fn func_call<'src>(
156214
ident()
157215
.map_with(|func_name, e| (func_name, e.span()))
158216
.then(arg_list)
217+
.padded()
159218
.validate(|((func_name, func_name_span), args), e, emitter| {
160219
let mut c = FuncContext::new(func_name, func_name_span, args);
161220
let res = match func_name {
221+
"any" => c.args1(Expr::Any),
222+
"all" => c.args1(Expr::All),
162223
"zoom" => Ok(Expr::Zoom),
163224
"get" => c.args1(Expr::Get),
164225
_ => c.unknown(),
@@ -180,6 +241,7 @@ fn func_call<'src>(
180241

181242
fn property<'src>() -> impl Parser<'src, &'src str, Expr, Error<'src>> {
182243
ident()
244+
.padded()
183245
.map(|name| Expr::Get(name.to_string()))
184246
.labelled("property name")
185247
}
@@ -311,13 +373,14 @@ fn literal<'src>() -> impl Parser<'src, &'src str, Expr, Error<'src>> {
311373
number_literal(),
312374
string_literal().map(ExprValue::from),
313375
))
376+
.padded()
314377
.map(Expr::Literal)
315378
.then_ignore(atom_boundary().rewind())
316379
.labelled("literal")
317380
}
318381

319382
fn atom_boundary<'src>() -> impl Parser<'src, &'src str, (), Error<'src>> {
320-
choice((operator().ignored(), one_of("()").ignored(), end()))
383+
choice((operator().ignored(), one_of("()[],").ignored(), end()))
321384
}
322385

323386
#[cfg(test)]
@@ -342,12 +405,18 @@ mod tests {
342405
("0042", 42.0.into()),
343406
("1.25e2", 125.0.into()),
344407
("1.25e-2", 0.0125.into()),
408+
(" 42", 42.0.into()),
409+
("\t42", 42.0.into()),
410+
("42 ", 42.0.into()),
411+
(" 42 ", 42.0.into()),
345412
("true", true.into()),
346413
("false", false.into()),
414+
(" false ", false.into()),
347415
("#FFAA00", Color::from_hex("#FFAA00").into()),
348416
("#FFAA00CC", Color::from_hex("#FFAA00CC").into()),
349417
("#ffaa00", Color::from_hex("#FFAA00").into()),
350418
("#fFaA00", Color::from_hex("#FFAA00").into()),
419+
(" #fFaA00 ", Color::from_hex("#FFAA00").into()),
351420
(r#""text""#, "text".to_string().into()),
352421
(r#""Текст!ёё""#, "Текст!ёё".to_string().into()),
353422
(r#""택스트""#, "택스트".to_string().into()),
@@ -360,11 +429,28 @@ mod tests {
360429
r#"'Escaped \' quotes'"#,
361430
"Escaped ' quotes".to_string().into(),
362431
),
432+
(r#" "text" "#, "text".to_string().into()),
363433
("property", Expr::Get("property".to_string())),
364434
("nullish", Expr::Get("nullish".to_string())),
365435
("trueman", Expr::Get("trueman".to_string())),
436+
(" property ", Expr::Get("property".to_string())),
366437
("zoom()", Expr::Zoom),
438+
(" zoom() ", Expr::Zoom),
367439
("get('property')", Expr::Get("property".to_string())),
440+
(
441+
"any([false, bool_prop])",
442+
Expr::Any(vec![false.into(), Expr::Get("bool_prop".to_owned())]),
443+
),
444+
(
445+
"all([string_prop == 'hi', bool_prop])",
446+
Expr::All(vec![
447+
Expr::Eq(
448+
Box::new(Expr::Get("string_prop".to_owned())),
449+
Box::new("hi".to_owned().into()),
450+
),
451+
Expr::Get("bool_prop".to_owned()),
452+
]),
453+
),
368454
];
369455

370456
for (case, expected) in cases {
@@ -439,7 +525,7 @@ mod tests {
439525

440526
#[test]
441527
fn parser_error_two_literals() {
442-
ass!(s("property 'value'"), @r#""found ''\\''' at 9..10 expected ==, or >""#)
528+
ass!(s("property 'value'"), @r#""found ''\\''' at 9..10 expected ==, !=, >, >=, <, <=, or end of input""#)
443529
}
444530

445531
#[test]
@@ -453,7 +539,12 @@ mod tests {
453539
}
454540

455541
#[test]
456-
fn parser_error_invalid_argument_type() {
542+
fn parser_error_invalid_argument_type_string() {
457543
ass!(s("get(42)"), @r#""expected `String` argument at position `1` of function `get`, but got `42` at 4..6""#);
458544
}
545+
546+
#[test]
547+
fn parser_error_invalid_argument_type_array() {
548+
ass!(s("any(true)"), @r#""expected `[Array]` argument at position `1` of function `any`, but got `true` at 4..8""#);
549+
}
459550
}

0 commit comments

Comments
 (0)