Use custom Arc backed input
Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
parent
1ea15f0e49
commit
1ee7611981
6 changed files with 283 additions and 77 deletions
|
|
@ -24,8 +24,8 @@ pub struct TemplateAst<'input> {
|
|||
root: Vec<TemplateAstExpr<'input>>,
|
||||
}
|
||||
|
||||
impl<'input> TemplateAst<'input> {
|
||||
pub fn root(&self) -> &[TemplateAstExpr<'input>] {
|
||||
impl TemplateAst<'_> {
|
||||
pub fn root(&self) -> &[TemplateAstExpr<'_>] {
|
||||
&self.root
|
||||
}
|
||||
}
|
||||
|
|
@ -73,22 +73,22 @@ impl ModalError for AstError {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'input> FromRecoverableError<Input<'input>, AstError> for AstError {
|
||||
impl FromRecoverableError<Input<'_>, AstError> for AstError {
|
||||
fn from_recoverable_error(
|
||||
token_start: &<Input<'input> as winnow::stream::Stream>::Checkpoint,
|
||||
_err_start: &<Input<'input> as winnow::stream::Stream>::Checkpoint,
|
||||
input: &Input<'input>,
|
||||
token_start: &<Input as winnow::stream::Stream>::Checkpoint,
|
||||
_err_start: &<Input as winnow::stream::Stream>::Checkpoint,
|
||||
input: &Input,
|
||||
mut e: AstError,
|
||||
) -> Self {
|
||||
e
|
||||
}
|
||||
}
|
||||
|
||||
impl<'input> AddContext<Input<'input>, AstError> for AstError {
|
||||
impl AddContext<Input<'_>, AstError> for AstError {
|
||||
fn add_context(
|
||||
mut self,
|
||||
_input: &Input<'input>,
|
||||
_token_start: &<Input<'input> as Stream>::Checkpoint,
|
||||
_input: &Input,
|
||||
_token_start: &<Input as Stream>::Checkpoint,
|
||||
context: AstError,
|
||||
) -> Self {
|
||||
self.message = context.message.or(self.message);
|
||||
|
|
@ -97,10 +97,10 @@ impl<'input> AddContext<Input<'input>, AstError> for AstError {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'input> ParserError<Input<'input>> for AstError {
|
||||
impl ParserError<Input<'_>> for AstError {
|
||||
type Inner = AstError;
|
||||
|
||||
fn from_input(_input: &Input<'input>) -> Self {
|
||||
fn from_input(_input: &Input<'_>) -> Self {
|
||||
AstError::ctx()
|
||||
}
|
||||
|
||||
|
|
@ -117,24 +117,22 @@ impl<'input> ParserError<Input<'input>> for AstError {
|
|||
pub struct AstFailure {}
|
||||
|
||||
impl AstFailure {
|
||||
fn from_errors(_errors: Vec<AstError>, _input: &[TemplateToken<'_>]) -> AstFailure {
|
||||
fn from_errors(_errors: Vec<AstError>, _input: &[TemplateToken]) -> AstFailure {
|
||||
AstFailure {}
|
||||
}
|
||||
}
|
||||
|
||||
type Input<'input> = Recoverable<TokenSlice<'input, TemplateToken<'input>>, AstError>;
|
||||
type Input<'input> = Recoverable<TokenSlice<'input, TemplateToken>, AstError>;
|
||||
|
||||
impl<'i> Parser<Input<'i>, TemplateToken<'i>, AstError> for TokenKind {
|
||||
fn parse_next(&mut self, input: &mut Input<'i>) -> winnow::Result<TemplateToken<'i>, AstError> {
|
||||
impl<'input> Parser<Input<'input>, TemplateToken, AstError> for TokenKind {
|
||||
fn parse_next(&mut self, input: &mut Input<'input>) -> winnow::Result<TemplateToken, AstError> {
|
||||
winnow::token::literal(*self)
|
||||
.parse_next(input)
|
||||
.map(|t| t[0].clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse<'input>(
|
||||
input: &'input [TemplateToken<'input>],
|
||||
) -> Result<TemplateAst<'input>, AstFailure> {
|
||||
pub fn parse(input: &[TemplateToken]) -> Result<TemplateAst<'_>, AstFailure> {
|
||||
let (_remaining, val, errors) = parse_ast.recoverable_parse(TokenSlice::new(input));
|
||||
|
||||
if errors.is_empty()
|
||||
|
|
@ -148,15 +146,15 @@ pub fn parse<'input>(
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TemplateAstExpr<'input> {
|
||||
StaticContent(TemplateToken<'input>),
|
||||
StaticContent(TemplateToken),
|
||||
Interpolation {
|
||||
prev_whitespace: Option<TemplateToken<'input>>,
|
||||
wants_output: Option<TemplateToken<'input>>,
|
||||
prev_whitespace: Option<TemplateToken>,
|
||||
wants_output: Option<TemplateToken>,
|
||||
expression: Box<TemplateAstExpr<'input>>,
|
||||
post_whitespace: Option<TemplateToken<'input>>,
|
||||
post_whitespace: Option<TemplateToken>,
|
||||
},
|
||||
VariableAccess(TemplateToken<'input>),
|
||||
Invalid(&'input [TemplateToken<'input>]),
|
||||
VariableAccess(TemplateToken),
|
||||
Invalid(&'input [TemplateToken]),
|
||||
}
|
||||
|
||||
fn parse_ast<'input>(input: &mut Input<'input>) -> Result<Vec<TemplateAstExpr<'input>>, AstError> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::ast::TemplateAstExpr;
|
||||
use crate::input::TempleInput;
|
||||
|
||||
pub struct EmitMachine {
|
||||
current_index: usize,
|
||||
|
|
@ -23,10 +24,19 @@ pub struct VariableSlot {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum Instruction {
|
||||
AppendContent { content: String },
|
||||
LoadFromContextToSlot { name: String, slot: VariableSlot },
|
||||
EmitFromSlot { slot: VariableSlot },
|
||||
PushScope { inherit_parent: bool },
|
||||
AppendContent {
|
||||
content: TempleInput,
|
||||
},
|
||||
LoadFromContextToSlot {
|
||||
name: TempleInput,
|
||||
slot: VariableSlot,
|
||||
},
|
||||
EmitFromSlot {
|
||||
slot: VariableSlot,
|
||||
},
|
||||
PushScope {
|
||||
inherit_parent: bool,
|
||||
},
|
||||
Abort,
|
||||
}
|
||||
|
||||
|
|
@ -42,11 +52,15 @@ pub fn emit_machine(input: crate::ast::TemplateAst<'_>) -> Vec<Instruction> {
|
|||
eval
|
||||
}
|
||||
|
||||
fn emit_ast_expr(machine: &mut EmitMachine, eval: &mut Vec<Instruction>, ast: &TemplateAstExpr<'_>) {
|
||||
fn emit_ast_expr(
|
||||
machine: &mut EmitMachine,
|
||||
eval: &mut Vec<Instruction>,
|
||||
ast: &TemplateAstExpr<'_>,
|
||||
) {
|
||||
match ast {
|
||||
TemplateAstExpr::StaticContent(template_token) => {
|
||||
eval.push(Instruction::AppendContent {
|
||||
content: template_token.source().to_string(),
|
||||
content: template_token.source().clone(),
|
||||
});
|
||||
}
|
||||
TemplateAstExpr::Interpolation {
|
||||
|
|
@ -57,7 +71,7 @@ fn emit_ast_expr(machine: &mut EmitMachine, eval: &mut Vec<Instruction>, ast: &T
|
|||
} => {
|
||||
if let Some(ws) = prev_whitespace {
|
||||
eval.push(Instruction::AppendContent {
|
||||
content: ws.source().to_string(),
|
||||
content: ws.source().clone(),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +84,7 @@ fn emit_ast_expr(machine: &mut EmitMachine, eval: &mut Vec<Instruction>, ast: &T
|
|||
|
||||
if let Some(ws) = post_whitespace {
|
||||
eval.push(Instruction::AppendContent {
|
||||
content: ws.source().to_string(),
|
||||
content: ws.source().clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -89,7 +103,7 @@ fn emit_expr(
|
|||
match expression {
|
||||
TemplateAstExpr::VariableAccess(template_token) => {
|
||||
eval.push(Instruction::LoadFromContextToSlot {
|
||||
name: template_token.source().to_string(),
|
||||
name: template_token.source().clone(),
|
||||
slot: emit_slot,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ use thiserror::Error;
|
|||
|
||||
use crate::Context;
|
||||
use crate::emit::Instruction;
|
||||
use crate::input::TempleInput;
|
||||
|
||||
#[derive(Debug, Error, Display)]
|
||||
enum EvalError {
|
||||
/// An unknown variable was encountered: .0
|
||||
UnknownVariable(String),
|
||||
UnknownVariable(TempleInput),
|
||||
/// An explicit abort was requested
|
||||
ExplicitAbort,
|
||||
}
|
||||
|
|
@ -25,7 +26,7 @@ fn execute(instructions: &[Instruction], global_context: &Context) -> Result<Str
|
|||
Instruction::LoadFromContextToSlot { name, slot } => {
|
||||
let value = global_context
|
||||
.values
|
||||
.get(name)
|
||||
.get(name.as_str())
|
||||
.ok_or(EvalError::UnknownVariable(name.clone()))?;
|
||||
|
||||
scopes.insert(*slot, value.clone());
|
||||
|
|
|
|||
194
src/input.rs
Normal file
194
src/input.rs
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
use std::ops::Deref;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
|
||||
use winnow::stream::Compare;
|
||||
use winnow::stream::FindSlice;
|
||||
use winnow::stream::Offset;
|
||||
use winnow::stream::Stream;
|
||||
use winnow::stream::StreamIsPartial;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct TempleInput {
|
||||
backing: Arc<str>,
|
||||
range: Range<usize>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for TempleInput {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "\"{}\"", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for TempleInput {
|
||||
fn from(value: &str) -> Self {
|
||||
let backing = Arc::from(value.to_string());
|
||||
let range = 0..value.len();
|
||||
|
||||
TempleInput { backing, range }
|
||||
}
|
||||
}
|
||||
|
||||
impl FindSlice<&str> for TempleInput {
|
||||
fn find_slice(&self, substr: &str) -> Option<core::ops::Range<usize>> {
|
||||
self.as_str().find_slice(substr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Compare<&str> for TempleInput {
|
||||
fn compare(&self, t: &str) -> winnow::stream::CompareResult {
|
||||
self.as_str().compare(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for TempleInput {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.backing[self.range.clone()]
|
||||
}
|
||||
}
|
||||
|
||||
impl TempleInput {
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Offset for TempleInput {
|
||||
fn offset_from(&self, start: &Self) -> usize {
|
||||
self.as_str().offset_from(&start.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TempleInputIter {
|
||||
idx: usize,
|
||||
input: TempleInput,
|
||||
}
|
||||
|
||||
impl Iterator for TempleInputIter {
|
||||
type Item = (usize, char);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let val = self.input.as_str().char_indices().nth(self.idx);
|
||||
self.idx += 1;
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
impl StreamIsPartial for TempleInput {
|
||||
type PartialState = ();
|
||||
|
||||
fn complete(&mut self) -> Self::PartialState {
|
||||
// Always complete
|
||||
}
|
||||
|
||||
fn restore_partial(&mut self, _state: Self::PartialState) {}
|
||||
|
||||
fn is_partial_supported() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for TempleInput {
|
||||
type Token = char;
|
||||
|
||||
type Slice = TempleInput;
|
||||
|
||||
type IterOffsets = TempleInputIter;
|
||||
|
||||
type Checkpoint = TempleInput;
|
||||
|
||||
fn iter_offsets(&self) -> Self::IterOffsets {
|
||||
TempleInputIter {
|
||||
idx: 0,
|
||||
input: self.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn eof_offset(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn next_token(&mut self) -> Option<Self::Token> {
|
||||
let c = self.chars().next()?;
|
||||
|
||||
self.range.start += c.len_utf8();
|
||||
Some(c)
|
||||
}
|
||||
|
||||
fn peek_token(&self) -> Option<Self::Token> {
|
||||
self.chars().next()
|
||||
}
|
||||
|
||||
fn offset_for<P>(&self, predicate: P) -> Option<usize>
|
||||
where
|
||||
P: Fn(Self::Token) -> bool,
|
||||
{
|
||||
self.as_str().offset_for(predicate)
|
||||
}
|
||||
|
||||
fn offset_at(&self, tokens: usize) -> Result<usize, winnow::error::Needed> {
|
||||
self.as_str().offset_at(tokens)
|
||||
}
|
||||
|
||||
fn next_slice(&mut self, offset: usize) -> Self::Slice {
|
||||
let mut next = self.clone();
|
||||
|
||||
self.range.start += offset;
|
||||
next.range.end = self.range.start;
|
||||
|
||||
next
|
||||
}
|
||||
|
||||
fn peek_slice(&self, offset: usize) -> Self::Slice {
|
||||
let mut next = self.clone();
|
||||
next.range.end = self.range.start + offset;
|
||||
next
|
||||
}
|
||||
|
||||
fn checkpoint(&self) -> Self::Checkpoint {
|
||||
self.clone()
|
||||
}
|
||||
|
||||
fn reset(&mut self, checkpoint: &Self::Checkpoint) {
|
||||
self.range = checkpoint.range.clone();
|
||||
}
|
||||
|
||||
fn raw(&self) -> &dyn core::fmt::Debug {
|
||||
self
|
||||
}
|
||||
|
||||
fn trace(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use winnow::stream::Stream;
|
||||
|
||||
use crate::input::TempleInput;
|
||||
|
||||
#[test]
|
||||
fn check_stream_impl() {
|
||||
let mut stream = TempleInput::from("checking");
|
||||
|
||||
let checkpoint = stream.checkpoint();
|
||||
|
||||
assert_eq!(stream.peek_token(), Some('c'));
|
||||
assert_eq!(stream.next_token(), Some('c'));
|
||||
let next_slice = stream.next_slice(4);
|
||||
assert_eq!(next_slice.as_str(), "heck");
|
||||
assert_eq!(stream.peek_token(), Some('i'));
|
||||
|
||||
stream.reset(&checkpoint);
|
||||
assert_eq!(stream.peek_token(), Some('c'));
|
||||
|
||||
let peek = stream.peek_slice(4);
|
||||
assert_eq!(peek.as_str(), "chec");
|
||||
|
||||
let eof_offset = stream.eof_offset();
|
||||
assert_eq!(eof_offset, 8);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ pub mod ast;
|
|||
pub mod emit;
|
||||
pub mod eval;
|
||||
pub mod parser;
|
||||
mod input;
|
||||
|
||||
#[derive(Debug, Error, Display)]
|
||||
pub enum TempleError {
|
||||
|
|
|
|||
|
|
@ -31,9 +31,10 @@ use winnow::token::take_until;
|
|||
use winnow::token::take_while;
|
||||
|
||||
use crate::SourceSpan;
|
||||
use crate::input::TempleInput;
|
||||
use crate::resume_after_cut;
|
||||
|
||||
type Input<'input> = Recoverable<LocatingSlice<&'input str>, ParseError>;
|
||||
type Input<'input> = Recoverable<LocatingSlice<TempleInput>, ParseError>;
|
||||
type PResult<'input, T> = Result<T, ParseError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -177,12 +178,12 @@ impl<'input> ParserError<Input<'input>> for ParseError {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParsedTemplate<'input> {
|
||||
tokens: Vec<TemplateToken<'input>>,
|
||||
pub struct ParsedTemplate {
|
||||
tokens: Vec<TemplateToken>,
|
||||
}
|
||||
|
||||
impl<'input> ParsedTemplate<'input> {
|
||||
pub fn tokens(&self) -> &[TemplateToken<'input>] {
|
||||
impl ParsedTemplate {
|
||||
pub fn tokens(&self) -> &[TemplateToken] {
|
||||
&self.tokens
|
||||
}
|
||||
}
|
||||
|
|
@ -198,88 +199,86 @@ pub enum TokenKind {
|
|||
Invalid,
|
||||
}
|
||||
|
||||
impl PartialEq<TokenKind> for TemplateToken<'_> {
|
||||
impl PartialEq<TokenKind> for TemplateToken {
|
||||
fn eq(&self, other: &TokenKind) -> bool {
|
||||
self.kind == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl winnow::stream::ContainsToken<&'_ TemplateToken<'_>> for TokenKind {
|
||||
fn contains_token(&self, token: &'_ TemplateToken<'_>) -> bool {
|
||||
impl winnow::stream::ContainsToken<&'_ TemplateToken> for TokenKind {
|
||||
fn contains_token(&self, token: &'_ TemplateToken) -> bool {
|
||||
*self == token.kind
|
||||
}
|
||||
}
|
||||
|
||||
impl winnow::stream::ContainsToken<&'_ TemplateToken<'_>> for &'_ [TokenKind] {
|
||||
fn contains_token(&self, token: &'_ TemplateToken<'_>) -> bool {
|
||||
impl winnow::stream::ContainsToken<&'_ TemplateToken> for &'_ [TokenKind] {
|
||||
fn contains_token(&self, token: &'_ TemplateToken) -> bool {
|
||||
self.contains(&token.kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> winnow::stream::ContainsToken<&'_ TemplateToken<'_>>
|
||||
for &'_ [TokenKind; LEN]
|
||||
{
|
||||
fn contains_token(&self, token: &'_ TemplateToken<'_>) -> bool {
|
||||
impl<const LEN: usize> winnow::stream::ContainsToken<&'_ TemplateToken> for &'_ [TokenKind; LEN] {
|
||||
fn contains_token(&self, token: &'_ TemplateToken) -> bool {
|
||||
self.contains(&token.kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> winnow::stream::ContainsToken<&'_ TemplateToken<'_>> for [TokenKind; LEN] {
|
||||
fn contains_token(&self, token: &'_ TemplateToken<'_>) -> bool {
|
||||
impl<const LEN: usize> winnow::stream::ContainsToken<&'_ TemplateToken> for [TokenKind; LEN] {
|
||||
fn contains_token(&self, token: &'_ TemplateToken) -> bool {
|
||||
self.contains(&token.kind)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TemplateToken<'input> {
|
||||
pub struct TemplateToken {
|
||||
kind: TokenKind,
|
||||
source: &'input str,
|
||||
source: TempleInput,
|
||||
}
|
||||
|
||||
impl<'input> TemplateToken<'input> {
|
||||
fn content(source: &'input str) -> Self {
|
||||
impl TemplateToken {
|
||||
fn content(source: TempleInput) -> Self {
|
||||
TemplateToken {
|
||||
kind: TokenKind::Content,
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn left_delim(source: &'input str) -> Self {
|
||||
fn left_delim(source: TempleInput) -> Self {
|
||||
TemplateToken {
|
||||
kind: TokenKind::LeftDelim,
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn right_delim(source: &'input str) -> Self {
|
||||
fn right_delim(source: TempleInput) -> Self {
|
||||
TemplateToken {
|
||||
kind: TokenKind::RightDelim,
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn wants_output(source: &'input str) -> Self {
|
||||
fn wants_output(source: TempleInput) -> Self {
|
||||
TemplateToken {
|
||||
kind: TokenKind::WantsOutput,
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn ident(source: &'input str) -> Self {
|
||||
fn ident(source: TempleInput) -> Self {
|
||||
TemplateToken {
|
||||
kind: TokenKind::Ident,
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn whitespace(source: &'input str) -> Self {
|
||||
fn whitespace(source: TempleInput) -> Self {
|
||||
TemplateToken {
|
||||
kind: TokenKind::Whitespace,
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid(source: &'input str) -> Self {
|
||||
fn invalid(source: TempleInput) -> Self {
|
||||
TemplateToken {
|
||||
kind: TokenKind::Invalid,
|
||||
source,
|
||||
|
|
@ -290,13 +289,14 @@ impl<'input> TemplateToken<'input> {
|
|||
self.kind
|
||||
}
|
||||
|
||||
pub fn source(&self) -> &'input str {
|
||||
self.source
|
||||
pub fn source(&self) -> TempleInput {
|
||||
self.source.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(input: &str) -> Result<ParsedTemplate<'_>, ParseFailure> {
|
||||
let (_remaining, val, errors) = parse_tokens.recoverable_parse(LocatingSlice::new(input));
|
||||
pub fn parse(input: &str) -> Result<ParsedTemplate, ParseFailure> {
|
||||
let (_remaining, val, errors) =
|
||||
parse_tokens.recoverable_parse(LocatingSlice::new(TempleInput::from(input)));
|
||||
|
||||
if errors.is_empty()
|
||||
&& let Some(val) = val
|
||||
|
|
@ -307,13 +307,13 @@ pub fn parse(input: &str) -> Result<ParsedTemplate<'_>, ParseFailure> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_tokens<'input>(input: &mut Input<'input>) -> PResult<'input, Vec<TemplateToken<'input>>> {
|
||||
fn parse_tokens<'input>(input: &mut Input<'input>) -> PResult<'input, Vec<TemplateToken>> {
|
||||
repeat_till(0.., alt((parse_interpolate, parse_content)), eof)
|
||||
.map(|(v, _): (Vec<_>, _)| v.into_iter().flatten().collect())
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_content<'input>(input: &mut Input<'input>) -> PResult<'input, Vec<TemplateToken<'input>>> {
|
||||
fn parse_content<'input>(input: &mut Input<'input>) -> PResult<'input, Vec<TemplateToken>> {
|
||||
alt((
|
||||
repeat_till(1.., any, peek((multispace0, "{{"))).map(|((), _)| ()),
|
||||
rest.void(),
|
||||
|
|
@ -324,9 +324,7 @@ fn parse_content<'input>(input: &mut Input<'input>) -> PResult<'input, Vec<Templ
|
|||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_interpolate<'input>(
|
||||
input: &mut Input<'input>,
|
||||
) -> PResult<'input, Vec<TemplateToken<'input>>> {
|
||||
fn parse_interpolate<'input>(input: &mut Input<'input>) -> PResult<'input, Vec<TemplateToken>> {
|
||||
let prev_whitespace = opt(parse_whitespace).parse_next(input)?;
|
||||
let left_delim = "{{".map(TemplateToken::left_delim).parse_next(input)?;
|
||||
let wants_output = opt("=".map(TemplateToken::wants_output)).parse_next(input)?;
|
||||
|
|
@ -337,7 +335,9 @@ fn parse_interpolate<'input>(
|
|||
let (inside_tokens, _): (Vec<_>, _) = get_tokens
|
||||
.resume_after(recover)
|
||||
.with_taken()
|
||||
.map(|(val, taken)| val.unwrap_or_else(|| (vec![TemplateToken::invalid(taken)], "")))
|
||||
.map(|(val, taken)| {
|
||||
val.unwrap_or_else(|| (vec![TemplateToken::invalid(taken)], TempleInput::from("")))
|
||||
})
|
||||
.parse_next(input)?;
|
||||
|
||||
let right_delim = "}}".map(TemplateToken::right_delim).parse_next(input)?;
|
||||
|
|
@ -354,9 +354,7 @@ fn parse_interpolate<'input>(
|
|||
Ok(tokens)
|
||||
}
|
||||
|
||||
fn parse_interpolate_token<'input>(
|
||||
input: &mut Input<'input>,
|
||||
) -> PResult<'input, TemplateToken<'input>> {
|
||||
fn parse_interpolate_token<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> {
|
||||
trace(
|
||||
"parse_interpolate_token",
|
||||
alt((parse_ident, parse_whitespace)),
|
||||
|
|
@ -364,7 +362,7 @@ fn parse_interpolate_token<'input>(
|
|||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_whitespace<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken<'input>> {
|
||||
fn parse_whitespace<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> {
|
||||
trace(
|
||||
"parse_whitespace",
|
||||
multispace1.map(TemplateToken::whitespace),
|
||||
|
|
@ -372,7 +370,7 @@ fn parse_whitespace<'input>(input: &mut Input<'input>) -> PResult<'input, Templa
|
|||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_ident<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken<'input>> {
|
||||
fn parse_ident<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> {
|
||||
resume_after_cut(
|
||||
terminated(
|
||||
ident.map(TemplateToken::ident),
|
||||
|
|
@ -390,7 +388,7 @@ fn parse_ident<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateTok
|
|||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn ident<'input>(input: &mut Input<'input>) -> PResult<'input, &'input str> {
|
||||
fn ident<'input>(input: &mut Input<'input>) -> PResult<'input, TempleInput> {
|
||||
take_while(1.., char::is_alphanumeric).parse_next(input)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue