From 08e1d8ece4314b56d64fa08595c2e043b97896d1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 6 Apr 2020 17:19:31 +0100 Subject: Split off operations from main expr enum --- dhall/src/syntax/text/parser.rs | 36 +++++----- dhall/src/syntax/text/printer.rs | 141 ++++++++++++++++++++++----------------- 2 files changed, 100 insertions(+), 77 deletions(-) (limited to 'dhall/src/syntax/text') diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs index 6f5949f..ab9bc24 100644 --- a/dhall/src/syntax/text/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -10,6 +10,7 @@ use pest_consume::{match_nodes, Parser}; use crate::syntax::map::{DupTreeMap, DupTreeSet}; use crate::syntax::ExprKind::*; use crate::syntax::NumKind::*; +use crate::syntax::OpKind::*; use crate::syntax::{ Double, Expr, FilePath, FilePrefix, Hash, ImportMode, ImportTarget, Integer, InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, @@ -138,7 +139,7 @@ fn insert_recordlit_entry(map: &mut BTreeMap, l: Label, e: Expr) { let dummy = Expr::new(Num(Bool(false)), Span::Artificial); let other = entry.insert(dummy); entry.insert(Expr::new( - BinOp(RecursiveRecordMerge, other, e), + Op(BinOp(RecursiveRecordMerge, other, e)), Span::DuplicateRecordFieldsSugar, )); } @@ -151,13 +152,16 @@ fn desugar_with_expr(x: Expr, labels: &[Label], y: Expr) -> Expr { match labels { [] => y, [l, rest @ ..] => { - let res = - desugar_with_expr(expr(Field(x.clone(), l.clone())), rest, y); - expr(BinOp( + let res = desugar_with_expr( + expr(Op(Field(x.clone(), l.clone()))), + rest, + y, + ); + expr(Op(BinOp( RightBiasedRecordMerge, x, expr(RecordLit(once((l.clone(), res)).collect())), - )) + ))) } } } @@ -725,7 +729,7 @@ impl DhallParser { }, [if_(()), expression(cond), expression(left), expression(right)] => { - spanned(input, BoolIf(cond, left, right)) + spanned(input, Op(BoolIf(cond, left, right))) }, [let_binding(bindings).., expression(final_expr)] => { bindings.rev().fold( @@ -747,13 +751,13 @@ impl DhallParser { spanned(input, Pi("_".into(), typ, body)) }, [merge(()), expression(x), expression(y), expression(z)] => { - spanned(input, Merge(x, y, Some(z))) + spanned(input, Op(Merge(x, y, Some(z)))) }, [assert(()), expression(x)] => { spanned(input, Assert(x)) }, [toMap(()), expression(x), expression(y)] => { - spanned(input, ToMap(x, Some(y))) + spanned(input, Op(ToMap(x, Some(y)))) }, [expression(e), expression(annot)] => { spanned(input, Annot(e, annot)) @@ -801,7 +805,7 @@ impl DhallParser { } }; - Ok(spanned_union(l.span(), r.span(), BinOp(op, l, r))) + Ok(spanned_union(l.span(), r.span(), Op(BinOp(op, l, r)))) } fn Some_(_input: ParseInput) -> ParseResult<()> { @@ -840,7 +844,7 @@ impl DhallParser { spanned_union( acc.span(), e.span(), - App(acc, e) + Op(App(acc, e)) ) } ) @@ -855,10 +859,10 @@ impl DhallParser { spanned(input, SomeLit(e)) }, [merge(()), expression(x), expression(y)] => { - spanned(input, Merge(x, y, None)) + spanned(input, Op(Merge(x, y, None))) }, [toMap(()), expression(x)] => { - spanned(input, ToMap(x, None)) + spanned(input, Op(ToMap(x, None))) }, [expression(e)] => e, )) @@ -875,7 +879,7 @@ impl DhallParser { spanned_union( acc.span(), e.span(), - Completion(acc, e), + Op(Completion(acc, e)), ) } ) @@ -895,9 +899,9 @@ impl DhallParser { acc.span(), e.1, match e.0 { - Selector::Field(l) => Field(acc, l), - Selector::Projection(ls) => Projection(acc, ls), - Selector::ProjectionByExpr(e) => ProjectionByExpr(acc, e) + Selector::Field(l) => Op(Field(acc, l)), + Selector::Projection(ls) => Op(Projection(acc, ls)), + Selector::ProjectionByExpr(e) => Op(ProjectionByExpr(acc, e)) } ) } diff --git a/dhall/src/syntax/text/printer.rs b/dhall/src/syntax/text/printer.rs index 378f408..d655489 100644 --- a/dhall/src/syntax/text/printer.rs +++ b/dhall/src/syntax/text/printer.rs @@ -5,14 +5,15 @@ use std::fmt::{self, Display}; // There is a one-to-one correspondence between the formatter and the grammar. Each phase is // named after a corresponding grammar group, and the structure of the formatter reflects // the relationship between the corresponding grammar rules. This leads to the nice property -// of automatically getting all the parentheses and precedences right. +// of automatically getting all the parentheses and precedences right (in a manner dual do Pratt +// parsing). #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] enum PrintPhase { // `expression` Base, // `operator-expression` Operator, - // All the operator `*-expression`s + // All the `-expression`s BinOp(ast::BinOp), // `application-expression` App, @@ -37,6 +38,7 @@ impl UnspannedExpr { // Annotate subexpressions with the appropriate phase, defaulting to Base fn annotate_with_phases(&self) -> ExprKind> { use crate::syntax::ExprKind::*; + use crate::syntax::OpKind::*; use PrintPhase::*; let with_base = self.map_ref(|e| PhasedExpr(e, Base)); match with_base { @@ -47,31 +49,33 @@ impl UnspannedExpr { Pi(a, b, c) } } - Merge(a, b, c) => Merge( + Op(Merge(a, b, c)) => Op(Merge( a.phase(PrintPhase::Import), b.phase(PrintPhase::Import), c.map(|x| x.phase(PrintPhase::App)), - ), - ToMap(a, b) => ToMap( + )), + Op(ToMap(a, b)) => Op(ToMap( a.phase(PrintPhase::Import), b.map(|x| x.phase(PrintPhase::App)), - ), + )), Annot(a, b) => Annot(a.phase(Operator), b), - ExprKind::BinOp(op, a, b) => ExprKind::BinOp( + Op(OpKind::BinOp(op, a, b)) => Op(OpKind::BinOp( op, a.phase(PrintPhase::BinOp(op)), b.phase(PrintPhase::BinOp(op)), - ), + )), SomeLit(e) => SomeLit(e.phase(PrintPhase::Import)), - ExprKind::App(f, a) => ExprKind::App( + Op(OpKind::App(f, a)) => Op(OpKind::App( f.phase(PrintPhase::App), a.phase(PrintPhase::Import), - ), - Field(a, b) => Field(a.phase(Primitive), b), - Projection(e, ls) => Projection(e.phase(Primitive), ls), - ProjectionByExpr(a, b) => ProjectionByExpr(a.phase(Primitive), b), - Completion(a, b) => { - Completion(a.phase(Primitive), b.phase(Primitive)) + )), + Op(Field(a, b)) => Op(Field(a.phase(Primitive), b)), + Op(Projection(e, ls)) => Op(Projection(e.phase(Primitive), ls)), + Op(ProjectionByExpr(a, b)) => { + Op(ProjectionByExpr(a.phase(Primitive), b)) + } + Op(Completion(a, b)) => { + Op(Completion(a.phase(Primitive), b.phase(Primitive))) } ExprKind::Import(a) => { ExprKind::Import(a.map_ref(|x| x.phase(PrintPhase::Import))) @@ -86,21 +90,23 @@ impl UnspannedExpr { phase: PrintPhase, ) -> Result<(), fmt::Error> { use crate::syntax::ExprKind::*; + use crate::syntax::OpKind::*; let needs_paren = match self { Lam(_, _, _) - | BoolIf(_, _, _) | Pi(_, _, _) | Let(_, _, _, _) - | EmptyListLit(_) | SomeLit(_) - | Merge(_, _, _) - | ToMap(_, _) + | EmptyListLit(_) + | Op(BoolIf(_, _, _)) + | Op(Merge(_, _, _)) + | Op(ToMap(_, _)) | Annot(_, _) => phase > PrintPhase::Base, - // Precedence is magically handled by the ordering of BinOps. - ExprKind::BinOp(op, _, _) => phase > PrintPhase::BinOp(*op), - ExprKind::App(_, _) => phase > PrintPhase::App, - Completion(_, _) => phase > PrintPhase::Import, + // Precedence is magically handled by the ordering of BinOps. This is reverse Pratt + // parsing. + Op(BinOp(op, _, _)) => phase > PrintPhase::BinOp(*op), + Op(App(_, _)) => phase > PrintPhase::App, + Op(Completion(_, _)) => phase > PrintPhase::Import, _ => false, }; @@ -143,12 +149,10 @@ impl Display for ExprKind { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { use crate::syntax::ExprKind::*; match self { + Var(a) => a.fmt(f)?, Lam(a, b, c) => { write!(f, "λ({} : {}) → {}", a, b, c)?; } - BoolIf(a, b, c) => { - write!(f, "if {} then {} else {}", a, b, c)?; - } Pi(a, b, c) if &String::from(a) == "_" => { write!(f, "{} → {}", b, c)?; } @@ -162,14 +166,62 @@ impl Display for ExprKind { } write!(f, " = {} in {}", c, d)?; } + Const(k) => k.fmt(f)?, + Builtin(v) => v.fmt(f)?, + Num(a) => a.fmt(f)?, + TextLit(a) => a.fmt(f)?, + SomeLit(e) => { + write!(f, "Some {}", e)?; + } EmptyListLit(t) => { write!(f, "[] : {}", t)?; } NEListLit(es) => { fmt_list("[", ", ", "]", es, f, Display::fmt)?; } - SomeLit(e) => { - write!(f, "Some {}", e)?; + RecordLit(a) if a.is_empty() => f.write_str("{=}")?, + RecordLit(a) => fmt_list("{ ", ", ", " }", a, f, |(k, v), f| { + write!(f, "{} = {}", k, v) + })?, + RecordType(a) if a.is_empty() => f.write_str("{}")?, + RecordType(a) => fmt_list("{ ", ", ", " }", a, f, |(k, t), f| { + write!(f, "{} : {}", k, t) + })?, + UnionType(a) => fmt_list("< ", " | ", " >", a, f, |(k, v), f| { + write!(f, "{}", k)?; + if let Some(v) = v { + write!(f, ": {}", v)?; + } + Ok(()) + })?, + Op(op) => { + op.fmt(f)?; + } + Annot(a, b) => { + write!(f, "{} : {}", a, b)?; + } + Assert(a) => { + write!(f, "assert : {}", a)?; + } + Import(a) => a.fmt(f)?, + } + Ok(()) + } +} + +/// Generic instance that delegates to subexpressions +impl Display for OpKind { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use crate::syntax::OpKind::*; + match self { + App(a, b) => { + write!(f, "{} {}", a, b)?; + } + BinOp(op, a, b) => { + write!(f, "{} {} {}", a, op, b)?; + } + BoolIf(a, b, c) => { + write!(f, "if {} then {} else {}", a, b, c)?; } Merge(a, b, c) => { write!(f, "merge {} {}", a, b)?; @@ -183,41 +235,9 @@ impl Display for ExprKind { write!(f, " : {}", b)?; } } - Annot(a, b) => { - write!(f, "{} : {}", a, b)?; - } - Assert(a) => { - write!(f, "assert : {}", a)?; - } - ExprKind::BinOp(op, a, b) => { - write!(f, "{} {} {}", a, op, b)?; - } - ExprKind::App(a, b) => { - write!(f, "{} {}", a, b)?; - } Field(a, b) => { write!(f, "{}.{}", a, b)?; } - Var(a) => a.fmt(f)?, - Const(k) => k.fmt(f)?, - Builtin(v) => v.fmt(f)?, - Num(a) => a.fmt(f)?, - TextLit(a) => a.fmt(f)?, - RecordType(a) if a.is_empty() => f.write_str("{}")?, - RecordType(a) => fmt_list("{ ", ", ", " }", a, f, |(k, t), f| { - write!(f, "{} : {}", k, t) - })?, - RecordLit(a) if a.is_empty() => f.write_str("{=}")?, - RecordLit(a) => fmt_list("{ ", ", ", " }", a, f, |(k, v), f| { - write!(f, "{} = {}", k, v) - })?, - UnionType(a) => fmt_list("< ", " | ", " >", a, f, |(k, v), f| { - write!(f, "{}", k)?; - if let Some(v) = v { - write!(f, ": {}", v)?; - } - Ok(()) - })?, Projection(e, ls) => { write!(f, "{}.", e)?; fmt_list("{ ", ", ", " }", ls, f, Display::fmt)?; @@ -228,7 +248,6 @@ impl Display for ExprKind { Completion(a, b) => { write!(f, "{}::{}", a, b)?; } - Import(a) => a.fmt(f)?, } Ok(()) } -- cgit v1.2.3 From fff4c46e09d4edf25eba737f4d71bfdb1dbf4a82 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 6 Apr 2020 22:11:54 +0100 Subject: Extract operation-related code to a new module --- dhall/src/syntax/text/parser.rs | 2 +- dhall/src/syntax/text/printer.rs | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'dhall/src/syntax/text') diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs index ab9bc24..8d76225 100644 --- a/dhall/src/syntax/text/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -7,10 +7,10 @@ use std::rc::Rc; use pest_consume::{match_nodes, Parser}; +use crate::operations::OpKind::*; use crate::syntax::map::{DupTreeMap, DupTreeSet}; use crate::syntax::ExprKind::*; use crate::syntax::NumKind::*; -use crate::syntax::OpKind::*; use crate::syntax::{ Double, Expr, FilePath, FilePrefix, Hash, ImportMode, ImportTarget, Integer, InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, diff --git a/dhall/src/syntax/text/printer.rs b/dhall/src/syntax/text/printer.rs index d655489..a85f435 100644 --- a/dhall/src/syntax/text/printer.rs +++ b/dhall/src/syntax/text/printer.rs @@ -1,3 +1,4 @@ +use crate::operations::OpKind; use crate::syntax::*; use itertools::Itertools; use std::fmt::{self, Display}; @@ -37,8 +38,8 @@ impl<'a> PhasedExpr<'a> { impl UnspannedExpr { // Annotate subexpressions with the appropriate phase, defaulting to Base fn annotate_with_phases(&self) -> ExprKind> { - use crate::syntax::ExprKind::*; - use crate::syntax::OpKind::*; + use ExprKind::*; + use OpKind::*; use PrintPhase::*; let with_base = self.map_ref(|e| PhasedExpr(e, Base)); match with_base { @@ -89,8 +90,8 @@ impl UnspannedExpr { f: &mut fmt::Formatter, phase: PrintPhase, ) -> Result<(), fmt::Error> { - use crate::syntax::ExprKind::*; - use crate::syntax::OpKind::*; + use ExprKind::*; + use OpKind::*; let needs_paren = match self { Lam(_, _, _) @@ -212,7 +213,7 @@ impl Display for ExprKind { /// Generic instance that delegates to subexpressions impl Display for OpKind { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::syntax::OpKind::*; + use OpKind::*; match self { App(a, b) => { write!(f, "{} {}", a, b)?; -- cgit v1.2.3 From 56efd2ac39149d8652bd625fbf0679c10823b137 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 6 Apr 2020 22:24:15 +0100 Subject: Move BinOp and Builtin definitions in the relevant module --- dhall/src/syntax/text/parser.rs | 48 ++++------------------------------------ dhall/src/syntax/text/printer.rs | 48 +++++----------------------------------- 2 files changed, 9 insertions(+), 87 deletions(-) (limited to 'dhall/src/syntax/text') diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs index 8d76225..dbf5c75 100644 --- a/dhall/src/syntax/text/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -36,46 +36,6 @@ enum Selector { ProjectionByExpr(Expr), } -impl crate::syntax::Builtin { - pub fn parse(s: &str) -> Option { - use crate::syntax::Builtin::*; - match s { - "Bool" => Some(Bool), - "Natural" => Some(Natural), - "Integer" => Some(Integer), - "Double" => Some(Double), - "Text" => Some(Text), - "List" => Some(List), - "Optional" => Some(Optional), - "None" => Some(OptionalNone), - "Natural/build" => Some(NaturalBuild), - "Natural/fold" => Some(NaturalFold), - "Natural/isZero" => Some(NaturalIsZero), - "Natural/even" => Some(NaturalEven), - "Natural/odd" => Some(NaturalOdd), - "Natural/toInteger" => Some(NaturalToInteger), - "Natural/show" => Some(NaturalShow), - "Natural/subtract" => Some(NaturalSubtract), - "Integer/toDouble" => Some(IntegerToDouble), - "Integer/show" => Some(IntegerShow), - "Integer/negate" => Some(IntegerNegate), - "Integer/clamp" => Some(IntegerClamp), - "Double/show" => Some(DoubleShow), - "List/build" => Some(ListBuild), - "List/fold" => Some(ListFold), - "List/length" => Some(ListLength), - "List/head" => Some(ListHead), - "List/last" => Some(ListLast), - "List/indexed" => Some(ListIndexed), - "List/reverse" => Some(ListReverse), - "Optional/fold" => Some(OptionalFold), - "Optional/build" => Some(OptionalBuild), - "Text/show" => Some(TextShow), - _ => None, - } - } -} - fn input_to_span(input: ParseInput) -> Span { Span::make(input.user_data().clone(), input.as_pair().as_span()) } @@ -129,7 +89,7 @@ fn trim_indent(lines: &mut Vec) { /// Insert the expr into the map; in case of collision, create a RecursiveRecordMerge node. fn insert_recordlit_entry(map: &mut BTreeMap, l: Label, e: Expr) { - use crate::syntax::BinOp::RecursiveRecordMerge; + use crate::operations::BinOp::RecursiveRecordMerge; use std::collections::btree_map::Entry; match map.entry(l) { Entry::Vacant(entry) => { @@ -147,7 +107,7 @@ fn insert_recordlit_entry(map: &mut BTreeMap, l: Label, e: Expr) { } fn desugar_with_expr(x: Expr, labels: &[Label], y: Expr) -> Expr { - use crate::syntax::BinOp::RightBiasedRecordMerge; + use crate::operations::BinOp::RightBiasedRecordMerge; let expr = |k| Expr::new(k, Span::WithSugar); match labels { [] => y, @@ -391,7 +351,7 @@ impl DhallParser { #[alias(expression)] fn builtin(input: ParseInput) -> ParseResult { let s = input.as_str(); - let e = match crate::syntax::Builtin::parse(s) { + let e = match crate::builtins::Builtin::parse(s) { Some(b) => Builtin(b), None => match s { "True" => Num(Bool(true)), @@ -784,7 +744,7 @@ impl DhallParser { op: ParseInput, r: Expr, ) -> ParseResult { - use crate::syntax::BinOp::*; + use crate::operations::BinOp::*; use Rule::*; let op = match op.as_rule() { import_alt => ImportAlt, diff --git a/dhall/src/syntax/text/printer.rs b/dhall/src/syntax/text/printer.rs index a85f435..9e90660 100644 --- a/dhall/src/syntax/text/printer.rs +++ b/dhall/src/syntax/text/printer.rs @@ -1,4 +1,5 @@ -use crate::operations::OpKind; +use crate::builtins::Builtin; +use crate::operations::{BinOp, OpKind}; use crate::syntax::*; use itertools::Itertools; use std::fmt::{self, Display}; @@ -15,7 +16,7 @@ enum PrintPhase { // `operator-expression` Operator, // All the `-expression`s - BinOp(ast::BinOp), + BinOp(self::BinOp), // `application-expression` App, // `import-expression` @@ -335,7 +336,7 @@ impl Display for Const { impl Display for BinOp { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::syntax::BinOp::*; + use BinOp::*; f.write_str(match self { BoolOr => "||", TextAppend => "++", @@ -383,7 +384,7 @@ impl Display for Label { let is_reserved = match s.as_str() { "let" | "in" | "if" | "then" | "else" | "Type" | "Kind" | "Sort" | "True" | "False" | "Some" => true, - _ => crate::syntax::Builtin::parse(&s).is_some(), + _ => Builtin::parse(&s).is_some(), }; if !is_reserved && s.chars().all(|c| c.is_ascii_alphanumeric()) { write!(f, "{}", s) @@ -481,45 +482,6 @@ impl Display for Import { } } -impl Display for Builtin { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::syntax::Builtin::*; - f.write_str(match *self { - Bool => "Bool", - Natural => "Natural", - Integer => "Integer", - Double => "Double", - Text => "Text", - List => "List", - Optional => "Optional", - OptionalNone => "None", - NaturalBuild => "Natural/build", - NaturalFold => "Natural/fold", - NaturalIsZero => "Natural/isZero", - NaturalEven => "Natural/even", - NaturalOdd => "Natural/odd", - NaturalToInteger => "Natural/toInteger", - NaturalShow => "Natural/show", - NaturalSubtract => "Natural/subtract", - IntegerToDouble => "Integer/toDouble", - IntegerNegate => "Integer/negate", - IntegerClamp => "Integer/clamp", - IntegerShow => "Integer/show", - DoubleShow => "Double/show", - ListBuild => "List/build", - ListFold => "List/fold", - ListLength => "List/length", - ListHead => "List/head", - ListLast => "List/last", - ListIndexed => "List/indexed", - ListReverse => "List/reverse", - OptionalFold => "Optional/fold", - OptionalBuild => "Optional/build", - TextShow => "Text/show", - }) - } -} - impl Display for Scheme { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { use crate::syntax::Scheme::*; -- cgit v1.2.3 From 092b7208ffd22f8facc7af387ac307e59208d52c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 7 Apr 2020 11:19:36 +0100 Subject: Move duplicate field checking to parser --- dhall/src/syntax/text/parser.rs | 64 ++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 10 deletions(-) (limited to 'dhall/src/syntax/text') diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs index dbf5c75..dcaf5e4 100644 --- a/dhall/src/syntax/text/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -1,14 +1,13 @@ use itertools::Itertools; use pest::prec_climber as pcl; use pest::prec_climber::PrecClimber; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::iter::once; use std::rc::Rc; use pest_consume::{match_nodes, Parser}; use crate::operations::OpKind::*; -use crate::syntax::map::{DupTreeMap, DupTreeSet}; use crate::syntax::ExprKind::*; use crate::syntax::NumKind::*; use crate::syntax::{ @@ -32,7 +31,7 @@ pub type ParseResult = Result; #[derive(Debug)] enum Selector { Field(Label), - Projection(DupTreeSet