From c8f6b5bd5c55845562571c196a0b2c1a7ca20f71 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 14 Aug 2020 20:43:03 +0200 Subject: [PATCH] =?UTF-8?q?Desugar=20body=20into=20last=20argument=20?= =?UTF-8?q?=F0=9F=8D=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/func.rs | 11 +-------- src/library/align.rs | 12 +++++----- src/library/boxed.rs | 8 +++---- src/library/font.rs | 8 +++---- src/library/page.rs | 5 ++-- src/library/spacing.rs | 5 ++-- src/library/val.rs | 7 +++--- src/syntax/parsing.rs | 53 ++++++++++++++++++------------------------ src/syntax/test.rs | 24 +++++++------------ src/syntax/value.rs | 2 ++ 10 files changed, 56 insertions(+), 79 deletions(-) diff --git a/src/func.rs b/src/func.rs index 016770cb3..abff559f4 100644 --- a/src/func.rs +++ b/src/func.rs @@ -8,9 +8,7 @@ pub mod prelude { pub use crate::layout::Command::{self, *}; pub use crate::style::*; pub use crate::syntax::expr::*; - pub use crate::syntax::parsing::{ - parse, FuncArgs, FuncBody, FuncCall, FuncHeader, ParseState, - }; + pub use crate::syntax::parsing::{parse, FuncArgs, FuncCall, ParseState}; pub use crate::syntax::span::{Span, SpanVec, Spanned}; pub use crate::syntax::tree::{DynamicNode, SyntaxNode, SyntaxTree}; pub use crate::syntax::value::*; @@ -55,10 +53,3 @@ pub fn drain_args(args: FuncArgs, f: &mut Feedback) { error!(@f, arg.span, "unexpected argument"); } } - -/// Generate an error if there is function body even though none was expected. -pub fn expect_no_body(body: FuncBody, f: &mut Feedback) { - if let Some(body) = body { - error!(@f, body.span, "unexpected body"); - } -} diff --git a/src/library/align.rs b/src/library/align.rs index 1ff07b89d..115793b12 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -12,9 +12,9 @@ use super::*; /// There may not be two alignment specifications for the same axis. pub fn align(call: FuncCall, _: &ParseState) -> Pass { let mut f = Feedback::new(); - let mut args = call.header.args; + let mut args = call.args; let node = AlignNode { - body: call.body.map(|s| s.v), + content: args.pos.get::(), aligns: args.pos.all::>().collect(), h: args.key.get::>("horizontal", &mut f), v: args.key.get::>("vertical", &mut f), @@ -25,7 +25,7 @@ pub fn align(call: FuncCall, _: &ParseState) -> Pass { #[derive(Debug, Clone, PartialEq)] struct AlignNode { - body: Option, + content: Option, aligns: SpanVec, h: Option>, v: Option>, @@ -64,9 +64,9 @@ impl Layout for AlignNode { } } - Pass::new(match &self.body { - Some(body) => { - let layouted = layout(body, ctx).await; + Pass::new(match &self.content { + Some(tree) => { + let layouted = layout(tree, ctx).await; f.extend(layouted.feedback); vec![AddMultiple(layouted.output)] } diff --git a/src/library/boxed.rs b/src/library/boxed.rs index 5191480f4..3ca3ae443 100644 --- a/src/library/boxed.rs +++ b/src/library/boxed.rs @@ -8,9 +8,9 @@ use super::*; /// - `height`: The height of the box (length of relative to parent's height). pub fn boxed(call: FuncCall, _: &ParseState) -> Pass { let mut f = Feedback::new(); - let mut args = call.header.args; + let mut args = call.args; let node = BoxNode { - body: call.body.map(|s| s.v).unwrap_or(SyntaxTree::new()), + content: args.pos.get::().unwrap_or(SyntaxTree::new()), width: args.key.get::("width", &mut f), height: args.key.get::("height", &mut f), }; @@ -20,7 +20,7 @@ pub fn boxed(call: FuncCall, _: &ParseState) -> Pass { #[derive(Debug, Clone, PartialEq)] struct BoxNode { - body: SyntaxTree, + content: SyntaxTree, width: Option, height: Option, } @@ -45,7 +45,7 @@ impl Layout for BoxNode { ctx.spaces[0].expansion.vertical = true; }); - layout(&self.body, ctx).await.map(|out| { + layout(&self.content, ctx).await.map(|out| { let layout = out.into_iter().next().unwrap(); vec![Add(layout)] }) diff --git a/src/library/font.rs b/src/library/font.rs index 356acc58d..d445a2468 100644 --- a/src/library/font.rs +++ b/src/library/font.rs @@ -20,10 +20,10 @@ use super::*; /// ``` pub fn font(call: FuncCall, _: &ParseState) -> Pass { let mut f = Feedback::new(); - let mut args = call.header.args; + let mut args = call.args; let node = FontNode { - body: call.body.map(|s| s.v), + content: args.pos.get::(), size: args.pos.get::(), style: args.key.get::("style", &mut f), weight: args.key.get::("weight", &mut f), @@ -53,7 +53,7 @@ pub fn font(call: FuncCall, _: &ParseState) -> Pass { #[derive(Debug, Clone, PartialEq)] struct FontNode { - body: Option, + content: Option, size: Option, style: Option, weight: Option, @@ -91,7 +91,7 @@ impl Layout for FontNode { text.fallback.flatten(); - Pass::okay(match &self.body { + Pass::okay(match &self.content { Some(tree) => vec![ SetTextStyle(text), LayoutSyntaxTree(tree), diff --git a/src/library/page.rs b/src/library/page.rs index 0a0189944..b47749ea5 100644 --- a/src/library/page.rs +++ b/src/library/page.rs @@ -18,8 +18,7 @@ use super::*; /// - `flip`: Flips custom or paper-defined width and height (boolean). pub fn page(call: FuncCall, _: &ParseState) -> Pass { let mut f = Feedback::new(); - let mut args = call.header.args; - expect_no_body(call.body, &mut f); + let mut args = call.args; let node = PageNode { paper: args.pos.get::(), width: args.key.get::("width", &mut f), @@ -79,7 +78,7 @@ impl Layout for PageNode { /// `pagebreak`: Ends the current page. pub fn pagebreak(call: FuncCall, _: &ParseState) -> Pass { let mut f = Feedback::new(); - drain_args(call.header.args, &mut f); + drain_args(call.args, &mut f); Pass::node(PageBreakNode, f) } diff --git a/src/library/spacing.rs b/src/library/spacing.rs index 14c6135aa..ad30a1221 100644 --- a/src/library/spacing.rs +++ b/src/library/spacing.rs @@ -20,12 +20,11 @@ pub fn v(call: FuncCall, _: &ParseState) -> Pass { fn spacing(call: FuncCall, axis: SpecAxis) -> Pass { let mut f = Feedback::new(); - let mut args = call.header.args; - expect_no_body(call.body, &mut f); + let mut args = call.args; let node = SpacingNode { spacing: args.pos.expect::(&mut f) .map(|s| (axis, s)) - .or_missing(call.header.name.span, "spacing", &mut f), + .or_missing(call.name.span, "spacing", &mut f), }; drain_args(args, &mut f); Pass::node(node, f) diff --git a/src/library/val.rs b/src/library/val.rs index bbbeb1d1e..6e83571af 100644 --- a/src/library/val.rs +++ b/src/library/val.rs @@ -5,21 +5,22 @@ use super::*; /// This is also the fallback function, which is used when a function name /// cannot be resolved. pub fn val(call: FuncCall, _: &ParseState) -> Pass { + let mut args = call.args; let node = ValNode { - body: call.body.map(|s| s.v), + content: args.pos.get::(), }; Pass::node(node, Feedback::new()) } #[derive(Debug, Clone, PartialEq)] struct ValNode { - body: Option, + content: Option, } #[async_trait(?Send)] impl Layout for ValNode { async fn layout<'a>(&'a self, _: LayoutContext<'_>) -> Pass> { - Pass::okay(match &self.body { + Pass::okay(match &self.content { Some(tree) => vec![LayoutSyntaxTree(tree)], None => vec![], }) diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs index 502f4de1f..2980cce2b 100644 --- a/src/syntax/parsing.rs +++ b/src/syntax/parsing.rs @@ -16,21 +16,10 @@ pub type CallParser = dyn Fn(FuncCall, &ParseState) -> Pass; /// An invocation of a function. #[derive(Debug, Clone, PartialEq)] pub struct FuncCall { - pub header: FuncHeader, - pub body: FuncBody, -} - -/// The parsed header of a function (everything in the first set of brackets). -#[derive(Debug, Clone, PartialEq)] -pub struct FuncHeader { pub name: Spanned, pub args: FuncArgs, } -/// The body of a function as a raw spanned string containing what's inside of -/// the brackets. -pub type FuncBody = Option>; - /// The positional and keyword arguments passed to a function. #[derive(Debug, Default, Clone, PartialEq)] pub struct FuncArgs { @@ -166,8 +155,8 @@ impl<'s> FuncParser<'s> { } fn parse(mut self) -> Pass { - let (parser, header) = if let Some(header) = self.parse_func_header() { - let name = header.name.v.as_str(); + let (parser, mut call) = if let Some(call) = self.parse_func_call() { + let name = call.name.v.as_str(); let (parser, deco) = match self.state.scope.get_parser(name) { // The function exists in the scope. Some(parser) => (parser, Decoration::ResolvedFunc), @@ -177,32 +166,34 @@ impl<'s> FuncParser<'s> { // the content of the function is not totally dropped (on a best // effort basis). None => { - error!(@self.feedback, header.name.span, "unknown function"); + error!(@self.feedback, call.name.span, "unknown function"); let parser = self.state.scope.get_fallback_parser(); (parser, Decoration::UnresolvedFunc) } }; - self.feedback.decorations.push(Spanned::new(deco, header.name.span)); - (parser, header) + self.feedback.decorations.push(Spanned::new(deco, call.name.span)); + (parser, call) } else { - // Parse the body with the fallback parser even when the header is + // Parse the call with the fallback parser even when the header is // completely unparsable. let parser = self.state.scope.get_fallback_parser(); - let header = FuncHeader { + let call = FuncCall { name: Spanned::new(Ident(String::new()), Span::ZERO), args: FuncArgs::new(), }; - (parser, header) + (parser, call) }; - let body = self.body.map(|body| body.map(|src| { - let parsed = parse(src, body.span.start, &self.state); - self.feedback.extend(parsed.feedback); - parsed.output - })); + if let Some(body) = self.body { + let tree = body.map(|src| { + let parsed = parse(src, body.span.start, &self.state); + self.feedback.extend(parsed.feedback); + Expr::Tree(parsed.output) + }); - let call = FuncCall { header, body }; + call.args.pos.push(tree); + } let parsed = parser(call, self.state); self.feedback.extend(parsed.feedback); @@ -210,7 +201,7 @@ impl<'s> FuncParser<'s> { Pass::new(parsed.output, self.feedback) } - fn parse_func_header(&mut self) -> Option { + fn parse_func_call(&mut self) -> Option { let after_bracket = self.pos(); self.skip_white(); @@ -229,7 +220,7 @@ impl<'s> FuncParser<'s> { None => FuncArgs::new(), }; - Some(FuncHeader { name, args }) + Some(FuncCall { name, args }) } fn parse_func_args(&mut self) -> FuncArgs { @@ -790,13 +781,13 @@ mod tests { value: Z($value), })));)*)? )? - SyntaxNode::boxed(DebugNode { - header: FuncHeader { + SyntaxNode::boxed(DebugNode( + FuncCall { name: span_item!($name).map(|s| Ident(s.to_string())), args, }, - body: func!(@body $($($body)*)?), - }) + func!(@body $($($body)*)?), + )) }}; (@body [$($body:tt)*]) => { Some(span_vec![$($body)*].0) }; (@body) => { None }; diff --git a/src/syntax/test.rs b/src/syntax/test.rs index 2ea5dde3b..97fecebc0 100644 --- a/src/syntax/test.rs +++ b/src/syntax/test.rs @@ -3,10 +3,10 @@ use std::fmt::Debug; use crate::func::prelude::*; use super::decoration::Decoration; use super::expr::{Expr, Ident, NamedTuple, Object, Pair, Tuple}; -use super::parsing::{FuncArg, FuncArgs, FuncHeader}; +use super::parsing::{FuncArg, FuncArgs}; use super::span::Spanned; use super::tokens::Token; -use super::tree::{DynamicNode, SyntaxNode, SyntaxTree}; +use super::tree::{DynamicNode, SyntaxNode}; pub fn check(src: &str, exp: T, found: T, cmp_spans: bool) where @@ -58,19 +58,13 @@ macro_rules! span_item { }; } -pub fn debug_func(call: FuncCall, _: &ParseState) -> Pass { - let node = DebugNode { - header: call.header, - body: call.body.map(|s| s.v), - }; - Pass::node(node, Feedback::new()) +pub fn debug_func(mut call: FuncCall, _: &ParseState) -> Pass { + let tree = call.args.pos.get::(); + Pass::node(DebugNode(call, tree), Feedback::new()) } #[derive(Debug, Clone, PartialEq)] -pub struct DebugNode { - pub header: FuncHeader, - pub body: Option, -} +pub struct DebugNode(pub FuncCall, pub Option); #[async_trait(?Send)] impl Layout for DebugNode { @@ -102,12 +96,12 @@ impl SpanlessEq for SyntaxNode { impl SpanlessEq for DebugNode { fn spanless_eq(&self, other: &Self) -> bool { - self.header.spanless_eq(&other.header) - && self.body.spanless_eq(&other.body) + self.0.spanless_eq(&other.0) + && self.1.spanless_eq(&other.1) } } -impl SpanlessEq for FuncHeader { +impl SpanlessEq for FuncCall { fn spanless_eq(&self, other: &Self) -> bool { self.name.spanless_eq(&other.name) && self.args.spanless_eq(&other.args) diff --git a/src/syntax/value.rs b/src/syntax/value.rs index c523ff931..aa5049e02 100644 --- a/src/syntax/value.rs +++ b/src/syntax/value.rs @@ -8,6 +8,7 @@ use crate::paper::Paper; use crate::Feedback; use super::expr::*; use super::span::Spanned; +use super::tree::SyntaxTree; /// Value types are used to extract values from functions, tuples and /// objects. They represent the value part of an argument. @@ -58,6 +59,7 @@ match_value!(String, "string", Expr::Str(s) => s); match_value!(bool, "bool", Expr::Bool(b) => b); match_value!(f64, "number", Expr::Number(n) => n); match_value!(Length, "length", Expr::Length(l) => l); +match_value!(SyntaxTree, "tree", Expr::Tree(t) => t); match_value!(Tuple, "tuple", Expr::Tuple(t) => t); match_value!(Object, "object", Expr::Object(o) => o); match_value!(ScaleLength, "number or length",