From d0978c35d88811462de5c448a24770f73b321e70 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 24 Mar 2019 21:05:01 +0100 Subject: Parse multiline strings correctly Closes #24 --- dhall_core/src/parser.rs | 68 ++++++++++++++++++++++++++++++++++-------------- dhall_core/src/text.rs | 2 +- 2 files changed, 50 insertions(+), 20 deletions(-) (limited to 'dhall_core') diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index 3d5a761..fb119b1 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -1,3 +1,4 @@ +use itertools::Itertools; use pest::iterators::Pair; use pest::Parser; use std::collections::BTreeMap; @@ -321,8 +322,24 @@ make_parser! { rule!(end_of_line<()>; captured_str!(_) => ()); rule!(single_quote_literal; children!( - [end_of_line(eol), single_quote_continue(contents)] => { - contents.into_iter().rev().collect::() + [end_of_line(eol), single_quote_continue(lines)] => { + let space = InterpolatedTextContents::Text(" ".to_owned()); + let newline = InterpolatedTextContents::Text("\n".to_owned()); + let min_indent = lines + .iter() + .map(|l| { + l.iter().rev().take_while(|c| **c == space).count() + }) + .min() + .unwrap(); + + lines + .into_iter() + .rev() + .map(|mut l| { l.split_off(l.len() - min_indent); l }) + .intersperse(vec![newline]) + .flat_map(|x| x.into_iter().rev()) + .collect::() } )); rule!(single_quote_char<&'a str>; @@ -338,25 +355,38 @@ make_parser! { [expression(e)] => e )); - rule!(single_quote_continue>; children!( - [interpolation(c), single_quote_continue(rest)] => { - let mut rest = rest; - rest.push(InterpolatedTextContents::Expr(c)); rest - }, - [escaped_quote_pair(c), single_quote_continue(rest)] => { - let mut rest = rest; - rest.push(InterpolatedTextContents::Text(c.to_owned())); rest - }, - [escaped_interpolation(c), single_quote_continue(rest)] => { - let mut rest = rest; - rest.push(InterpolatedTextContents::Text(c.to_owned())); rest - }, - [single_quote_char(c), single_quote_continue(rest)] => { - let mut rest = rest; - rest.push(InterpolatedTextContents::Text(c.to_owned())); rest + rule!(single_quote_continue>>; children!( + [interpolation(c), single_quote_continue(lines)] => { + let c = InterpolatedTextContents::Expr(c); + let mut lines = lines; + lines.last_mut().unwrap().push(c); + lines + }, + [escaped_quote_pair(c), single_quote_continue(lines)] => { + let c = InterpolatedTextContents::Text(c.to_owned()); + let mut lines = lines; + lines.last_mut().unwrap().push(c); + lines + }, + [escaped_interpolation(c), single_quote_continue(lines)] => { + let c = InterpolatedTextContents::Text(c.to_owned()); + let mut lines = lines; + lines.last_mut().unwrap().push(c); + lines + }, + [single_quote_char("\n"), single_quote_continue(lines)] => { + let mut lines = lines; + lines.push(vec![]); + lines + }, + [single_quote_char(c), single_quote_continue(lines)] => { + let c = InterpolatedTextContents::Text(c.to_owned()); + let mut lines = lines; + lines.last_mut().unwrap().push(c); + lines }, [] => { - vec![] + vec![vec![]] }, )); diff --git a/dhall_core/src/text.rs b/dhall_core/src/text.rs index 2a468d2..d377877 100644 --- a/dhall_core/src/text.rs +++ b/dhall_core/src/text.rs @@ -29,7 +29,7 @@ impl From for InterpolatedText { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum InterpolatedTextContents { Text(String), Expr(SubExpr), -- cgit v1.2.3