add function call syntax

This commit is contained in:
elkowar 2021-05-13 20:47:39 +02:00
parent df5793b204
commit 7d525cbaa6
No known key found for this signature in database
GPG key ID: E321AD71B1D1F27F
2 changed files with 33 additions and 1 deletions

View file

@ -1,5 +1,6 @@
use super::super::*;
use anyhow::*;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
@ -61,6 +62,7 @@ pub enum AttrValExpr {
UnaryOp(UnaryOp, Box<AttrValExpr>),
IfElse(Box<AttrValExpr>, Box<AttrValExpr>, Box<AttrValExpr>),
JsonAccess(Box<AttrValExpr>, Box<AttrValExpr>),
FunctionCall(String, Vec<AttrValExpr>),
}
impl std::fmt::Display for AttrValExpr {
@ -72,6 +74,7 @@ impl std::fmt::Display for AttrValExpr {
AttrValExpr::UnaryOp(op, x) => write!(f, "{}{}", op, x),
AttrValExpr::IfElse(a, b, c) => write!(f, "(if {} then {} else {})", a, b, c),
AttrValExpr::JsonAccess(value, index) => write!(f, "{}[{}]", value, index),
AttrValExpr::FunctionCall(function_name, args) => write!(f, "{}({})", function_name, args.iter().join(", ")),
}
}
}
@ -106,6 +109,9 @@ impl AttrValExpr {
Ok(IfElse(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?, box c.resolve_refs(variables)?))
}
JsonAccess(box a, box b) => Ok(JsonAccess(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?)),
FunctionCall(function_name, args) => {
Ok(FunctionCall(function_name, args.into_iter().map(|a| a.resolve_refs(variables)).collect::<Result<_>>()?))
}
}
}
@ -131,6 +137,7 @@ impl AttrValExpr {
refs.append(&mut b.var_refs());
refs
}
FunctionCall(_, args) => args.iter().flat_map(|a| a.var_refs()).collect_vec(),
}
}
@ -196,6 +203,10 @@ impl AttrValExpr {
_ => bail!("Unable to index into value {}", val),
}
}
AttrValExpr::FunctionCall(function_name, args) => {
let args = args.into_iter().map(|a| a.eval(values)).collect::<Result<_>>()?;
call_expr_function(&function_name, args)
}
}
}
@ -208,3 +219,17 @@ impl AttrValExpr {
parsed.context("Failed to parse expression")
}
}
fn call_expr_function(name: &str, args: Vec<PrimVal>) -> Result<PrimVal> {
match name {
"round" => match args.as_slice() {
[num, digits] => {
let num = num.as_f64()?;
let digits = digits.as_i32()?;
Ok(PrimVal::from(format!("{:.1$}", num, digits as usize)))
}
_ => Err(anyhow!("Incorrect number of arguments given to {}", name)),
},
_ => Err(anyhow!("Unknown function {}", name)),
}
}

View file

@ -6,7 +6,7 @@ use nom::{
character::complete::{multispace0 as multispace, *},
combinator::{map, map_res, *},
error::{context, ParseError, VerboseError},
multi::many0,
multi::{many0, separated_list0},
sequence::{delimited, preceded, *},
IResult, Parser,
};
@ -49,6 +49,12 @@ fn parse_unary_op(i: &str) -> IResult<&str, UnaryOp, VerboseError<&str>> {
value(UnaryOp::Not, tag("!"))(i)
}
fn parse_function_call(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
let (i, name) = take_while(|c: char| c.is_ascii_alphanumeric() || c == '_')(i)?;
let (i, args) = delimited(tag("("), separated_list0(tag(","), ws(parse_factor)), tag(")"))(i)?;
Ok((i, AttrValExpr::FunctionCall(name.to_string(), args)))
}
/////////////////
// actual tree //
/////////////////
@ -58,6 +64,7 @@ fn parse_factor(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
let (i, factor) = alt((
context("expression", ws(delimited(tag("("), parse_expr, tag(")")))),
context("if-expression", ws(parse_ifelse)),
context("function-call", ws(parse_function_call)),
context("literal", map(ws(parse_literal), |x| AttrValExpr::Literal(AttrVal::parse_string(x)))),
context("identifier", map(ws(parse_identifier), |x| AttrValExpr::VarRef(VarName(x.to_string())))),
))(i)?;