use crate::ast::{Expr, ExprKind, SourceInfo, Variable};
use crate::parser::{ParseError, ParseErrorKind, ParseResult, function};
use crate::reader::Reader;
pub fn parse(reader: &mut Reader) -> ParseResult<Expr> {
let start = reader.cursor().pos;
let save_state = reader.cursor();
let kind = match function::parse(reader) {
Ok(function) => ExprKind::Function(function),
Err(e) => {
if e.recoverable {
reader.seek(save_state);
let variable = variable_name(reader)?;
ExprKind::Variable(variable)
} else {
return Err(e);
}
}
};
let end = reader.cursor().pos;
let source_info = SourceInfo::new(start, end);
Ok(Expr { source_info, kind })
}
fn variable_name(reader: &mut Reader) -> ParseResult<Variable> {
let start = reader.cursor();
let name = reader.read_while(|c| c.is_alphanumeric() || c == '_' || c == '-');
if name.is_empty() {
return Err(ParseError::new(
start.pos,
false,
ParseErrorKind::TemplateVariable,
));
}
Ok(Variable {
name,
source_info: SourceInfo::new(start.pos, reader.cursor().pos),
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::reader::Pos;
#[test]
fn test_variable() {
let mut reader = Reader::new("name");
assert_eq!(
variable_name(&mut reader).unwrap(),
Variable {
name: String::from("name"),
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 5)),
}
);
let mut reader = Reader::new("my-id");
assert_eq!(
variable_name(&mut reader).unwrap(),
Variable {
name: String::from("my-id"),
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 6)),
}
);
}
}