use crate::ast::*;
use crate::parser::error::*;
use crate::parser::primitives::*;
use crate::parser::reader::Reader;
use crate::parser::template::template;
use crate::parser::{string, ParseResult};
pub fn parse(reader: &mut Reader) -> ParseResult<Template> {
let start = reader.state;
let mut elements = vec![];
loop {
match template(reader) {
Ok(expr) => {
let element = TemplateElement::Expression(expr);
elements.push(element);
}
Err(e) => {
if e.recoverable {
let value = key_string_content(reader)?;
if value.is_empty() {
break;
}
let encoded: String = reader.buffer[start.cursor..reader.state.cursor]
.iter()
.collect();
let element = TemplateElement::String { value, encoded };
elements.push(element);
} else {
return Err(e);
}
}
}
}
if elements.is_empty() {
let inner = ParseError::Expecting {
value: "key-string".to_string(),
};
return Err(Error::new(start.pos, false, inner));
}
if let Some(TemplateElement::String { encoded, .. }) = elements.first() {
if encoded.starts_with('[') {
let inner = ParseError::Expecting {
value: "key-string".to_string(),
};
return Err(Error::new(start.pos, false, inner));
}
}
let end = reader.state;
Ok(Template {
delimiter: None,
elements,
source_info: SourceInfo {
start: start.pos,
end: end.pos,
},
})
}
fn key_string_content(reader: &mut Reader) -> ParseResult<String> {
let mut s = String::new();
loop {
match key_string_escaped_char(reader) {
Ok(c) => {
s.push(c);
}
Err(e) => {
if e.recoverable {
let s2 = key_string_text(reader);
if s2.is_empty() {
break;
} else {
s.push_str(&s2);
}
} else {
return Err(e);
}
}
}
}
Ok(s)
}
fn key_string_text(reader: &mut Reader) -> String {
let mut s = String::new();
loop {
let save = reader.state;
match reader.read() {
None => break,
Some(c) => {
if c.is_alphanumeric()
|| c == '_'
|| c == '-'
|| c == '.'
|| c == '['
|| c == ']'
|| c == '@'
|| c == '$'
{
s.push(c);
} else {
reader.state = save;
break;
}
}
}
}
s
}
fn key_string_escaped_char(reader: &mut Reader) -> ParseResult<char> {
try_literal("\\", reader)?;
let start = reader.state;
match reader.read() {
Some('#') => Ok('#'),
Some(':') => Ok(':'),
Some('\\') => Ok('\\'),
Some('/') => Ok('/'),
Some('b') => Ok('\x08'),
Some('f') => Ok('\x0c'),
Some('n') => Ok('\n'),
Some('r') => Ok('\r'),
Some('t') => Ok('\t'),
Some('u') => string::unicode(reader),
_ => Err(Error::new(start.pos, false, ParseError::EscapeChar)),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_string() {
let mut reader = Reader::new("aaa\\: ");
assert_eq!(
parse(&mut reader).unwrap(),
Template {
delimiter: None,
elements: vec![TemplateElement::String {
value: "aaa:".to_string(),
encoded: "aaa\\:".to_string(),
}],
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 6)),
}
);
assert_eq!(reader.state.cursor, 5);
let mut reader = Reader::new("$top:");
assert_eq!(
parse(&mut reader).unwrap(),
Template {
delimiter: None,
elements: vec![TemplateElement::String {
value: "$top".to_string(),
encoded: "$top".to_string(),
}],
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 5)),
}
);
assert_eq!(reader.state.cursor, 4);
let mut reader = Reader::new("key\\u{20}\\u{3a} :");
assert_eq!(
parse(&mut reader).unwrap(),
Template {
delimiter: None,
elements: vec![TemplateElement::String {
value: "key :".to_string(),
encoded: "key\\u{20}\\u{3a}".to_string(),
}],
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 16)),
}
);
assert_eq!(reader.state.cursor, 15);
let mut reader = Reader::new("values\\u{5b}0\\u{5d} :");
assert_eq!(
parse(&mut reader).unwrap(),
Template {
delimiter: None,
elements: vec![TemplateElement::String {
value: "values[0]".to_string(),
encoded: "values\\u{5b}0\\u{5d}".to_string(),
}],
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 20)),
}
);
assert_eq!(reader.state.cursor, 19);
let mut reader = Reader::new("values[0] :");
assert_eq!(
parse(&mut reader).unwrap(),
Template {
delimiter: None,
elements: vec![TemplateElement::String {
value: "values[0]".to_string(),
encoded: "values[0]".to_string(),
}],
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 10)),
}
);
assert_eq!(reader.state.cursor, 9);
let mut reader = Reader::new("\\u{5b}0\\u{5d}");
assert_eq!(
parse(&mut reader).unwrap(),
Template {
delimiter: None,
elements: vec![TemplateElement::String {
value: "[0]".to_string(),
encoded: "\\u{5b}0\\u{5d}".to_string(),
}],
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 14)),
}
);
assert_eq!(reader.state.cursor, 13);
}
#[test]
fn test_key_string_error() {
let mut reader = Reader::new("");
let error = parse(&mut reader).err().unwrap();
assert!(!error.recoverable);
assert_eq!(error.pos, Pos { line: 1, column: 1 });
let mut reader = Reader::new("{{key");
let error = parse(&mut reader).err().unwrap();
assert!(!error.recoverable);
assert_eq!(error.pos, Pos { line: 1, column: 6 });
let mut reader = Reader::new("[0]:");
let error = parse(&mut reader).err().unwrap();
assert!(!error.recoverable);
assert_eq!(reader.state.cursor, 3);
let mut reader = Reader::new("\\l");
let error = parse(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 2 });
assert_eq!(error.inner, ParseError::EscapeChar);
let mut reader = Reader::new(r#"{"id":1}"#);
let error = parse(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 1 });
assert_eq!(
error.inner,
ParseError::Expecting {
value: "key-string".to_string()
}
);
}
#[test]
fn test_key_string_content() {
let mut reader = Reader::new("aaa\\:");
assert_eq!(key_string_content(&mut reader).unwrap(), "aaa:");
}
#[test]
fn test_key_string_text() {
let mut reader = Reader::new("aaa\\:");
assert_eq!(key_string_text(&mut reader), "aaa");
assert_eq!(reader.state.cursor, 3);
}
#[test]
fn test_key_string_escaped_char() {
let mut reader = Reader::new("\\u{0a}");
assert_eq!(key_string_escaped_char(&mut reader).unwrap(), '\n');
assert_eq!(reader.state.cursor, 6);
let mut reader = Reader::new("\\:");
assert_eq!(key_string_escaped_char(&mut reader).unwrap(), ':');
assert_eq!(reader.state.cursor, 2);
let mut reader = Reader::new("x");
let error = key_string_escaped_char(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 1 });
assert_eq!(
error.inner,
ParseError::Expecting {
value: "\\".to_string()
}
);
assert!(error.recoverable);
assert_eq!(reader.state.cursor, 0);
}
}