use super::Arithmetic;
use crate::parser::error::{grammar_bug, ParseError};
use crate::parser::{span_of, Lexeme, Rule};
use crate::common::{FileId, Ignored, Span};
use pest::iterators::Pair;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) struct FnCall {
name: String,
args: Vec<Arithmetic>,
is_negated: bool,
span: Ignored<Span>,
}
impl FnCall {
#[must_use]
pub(crate) fn new(name: String, args: Vec<Arithmetic>, is_negated: bool) -> Self {
Self {
name,
args,
is_negated,
span: Ignored(Span::DUMMY),
}
}
#[must_use]
pub(crate) fn with_span(mut self, span: Span) -> Self {
self.span = Ignored(span);
self
}
#[must_use]
#[inline]
pub(crate) fn span(&self) -> Span {
self.span.0
}
#[must_use]
#[inline]
pub(crate) fn name(&self) -> &str {
&self.name
}
#[must_use]
#[inline]
pub(crate) fn args(&self) -> &[Arithmetic] {
&self.args
}
#[inline]
pub(crate) fn args_mut(&mut self) -> &mut [Arithmetic] {
&mut self.args
}
#[must_use]
#[inline]
pub(crate) fn is_negated(&self) -> bool {
self.is_negated
}
#[must_use]
pub(crate) fn vars(&self) -> Vec<&String> {
self.args.iter().flat_map(|a| a.vars()).collect()
}
}
impl fmt::Display for FnCall {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let args = self
.args
.iter()
.map(|a| a.to_string())
.collect::<Vec<_>>()
.join(", ");
if self.is_negated {
write!(f, "!{}({})", self.name, args)
} else {
write!(f, "{}({})", self.name, args)
}
}
}
impl Lexeme for FnCall {
fn from_parsed_rule(parsed_rule: Pair<Rule>, file: FileId) -> Result<Self, ParseError> {
let span = span_of(&parsed_rule, file);
let mut children = parsed_rule.into_inner();
let fn_name = children
.next()
.ok_or_else(|| grammar_bug("fn_call_expr missing function name"))?
.as_str()
.to_string();
let mut args = Vec::new();
for p in children {
if p.as_rule() == Rule::arithmetic_expr {
args.push(Arithmetic::from_parsed_rule(p, file)?);
}
}
Ok(Self {
name: fn_name,
args,
is_negated: false,
span: Ignored(span),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::FileId;
use crate::parser::{FlowLogParser, Lexeme, Rule};
use pest::Parser;
#[test]
fn parse_fn_call_expr() {
let input = "my_udf(x, y)";
let mut pairs = FlowLogParser::parse(Rule::fn_call_expr, input).unwrap();
let fc = FnCall::from_parsed_rule(pairs.next().unwrap(), FileId(0)).unwrap();
assert_eq!(fc.name(), "my_udf");
assert_eq!(fc.args().len(), 2);
assert!(!fc.is_negated());
}
}