mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Always parse bodies as syntax trees 🌳
Previously they were passed as strings to the function parser, now they are parsed and then passed as trees to the function. This allows making bodies sugar for a last content argument. While it removes some flexibility allowing function to parse arbitrary syntaxes in their bodies, these can be modelled as (raw) string arguments.
This commit is contained in:
parent
0ac2e86feb
commit
1fb2d5103d
15
src/func.rs
15
src/func.rs
@ -56,21 +56,8 @@ pub fn drain_args(args: FuncArgs, f: &mut Feedback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a function's body if there is one or return `None` otherwise.
|
|
||||||
pub fn parse_body_maybe(
|
|
||||||
body: Option<Spanned<&str>>,
|
|
||||||
state: &ParseState,
|
|
||||||
f: &mut Feedback,
|
|
||||||
) -> Option<SyntaxTree> {
|
|
||||||
body.map(|body| {
|
|
||||||
let parsed = parse(body.v, body.span.start, state);
|
|
||||||
f.extend(parsed.feedback);
|
|
||||||
parsed.output
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generate an error if there is function body even though none was expected.
|
/// Generate an error if there is function body even though none was expected.
|
||||||
pub fn expect_no_body(body: Option<Spanned<&str>>, f: &mut Feedback) {
|
pub fn expect_no_body(body: FuncBody, f: &mut Feedback) {
|
||||||
if let Some(body) = body {
|
if let Some(body) = body {
|
||||||
error!(@f, body.span, "unexpected body");
|
error!(@f, body.span, "unexpected body");
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ use super::*;
|
|||||||
/// - `vertical`: Any of `top`, `bottom` or `center`.
|
/// - `vertical`: Any of `top`, `bottom` or `center`.
|
||||||
///
|
///
|
||||||
/// There may not be two alignment specifications for the same axis.
|
/// There may not be two alignment specifications for the same axis.
|
||||||
pub fn align(call: FuncCall, state: &ParseState) -> Pass<SyntaxNode> {
|
pub fn align(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> {
|
||||||
let mut f = Feedback::new();
|
let mut f = Feedback::new();
|
||||||
let mut args = call.header.args;
|
let mut args = call.header.args;
|
||||||
let node = AlignNode {
|
let node = AlignNode {
|
||||||
body: parse_body_maybe(call.body, state, &mut f),
|
body: call.body.map(|s| s.v),
|
||||||
aligns: args.pos.all::<Spanned<SpecAlign>>().collect(),
|
aligns: args.pos.all::<Spanned<SpecAlign>>().collect(),
|
||||||
h: args.key.get::<Spanned<SpecAlign>>("horizontal", &mut f),
|
h: args.key.get::<Spanned<SpecAlign>>("horizontal", &mut f),
|
||||||
v: args.key.get::<Spanned<SpecAlign>>("vertical", &mut f),
|
v: args.key.get::<Spanned<SpecAlign>>("vertical", &mut f),
|
||||||
|
@ -6,11 +6,11 @@ use super::*;
|
|||||||
/// # Keyword arguments
|
/// # Keyword arguments
|
||||||
/// - `width`: The width of the box (length of relative to parent's width).
|
/// - `width`: The width of the box (length of relative to parent's width).
|
||||||
/// - `height`: The height of the box (length of relative to parent's height).
|
/// - `height`: The height of the box (length of relative to parent's height).
|
||||||
pub fn boxed(call: FuncCall, state: &ParseState) -> Pass<SyntaxNode> {
|
pub fn boxed(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> {
|
||||||
let mut f = Feedback::new();
|
let mut f = Feedback::new();
|
||||||
let mut args = call.header.args;
|
let mut args = call.header.args;
|
||||||
let node = BoxNode {
|
let node = BoxNode {
|
||||||
body: parse_body_maybe(call.body, state, &mut f).unwrap_or(SyntaxTree::new()),
|
body: call.body.map(|s| s.v).unwrap_or(SyntaxTree::new()),
|
||||||
width: args.key.get::<ScaleLength>("width", &mut f),
|
width: args.key.get::<ScaleLength>("width", &mut f),
|
||||||
height: args.key.get::<ScaleLength>("height", &mut f),
|
height: args.key.get::<ScaleLength>("height", &mut f),
|
||||||
};
|
};
|
||||||
|
@ -18,12 +18,12 @@ use super::*;
|
|||||||
/// ```typst
|
/// ```typst
|
||||||
/// serif = ("Source Serif Pro", "Noto Serif")
|
/// serif = ("Source Serif Pro", "Noto Serif")
|
||||||
/// ```
|
/// ```
|
||||||
pub fn font(call: FuncCall, state: &ParseState) -> Pass<SyntaxNode> {
|
pub fn font(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> {
|
||||||
let mut f = Feedback::new();
|
let mut f = Feedback::new();
|
||||||
let mut args = call.header.args;
|
let mut args = call.header.args;
|
||||||
|
|
||||||
let node = FontNode {
|
let node = FontNode {
|
||||||
body: parse_body_maybe(call.body, state, &mut f),
|
body: call.body.map(|s| s.v),
|
||||||
size: args.pos.get::<ScaleLength>(),
|
size: args.pos.get::<ScaleLength>(),
|
||||||
style: args.key.get::<FontStyle>("style", &mut f),
|
style: args.key.get::<FontStyle>("style", &mut f),
|
||||||
weight: args.key.get::<FontWeight>("weight", &mut f),
|
weight: args.key.get::<FontWeight>("weight", &mut f),
|
||||||
|
@ -4,12 +4,11 @@ use super::*;
|
|||||||
///
|
///
|
||||||
/// This is also the fallback function, which is used when a function name
|
/// This is also the fallback function, which is used when a function name
|
||||||
/// cannot be resolved.
|
/// cannot be resolved.
|
||||||
pub fn val(call: FuncCall, state: &ParseState) -> Pass<SyntaxNode> {
|
pub fn val(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> {
|
||||||
let mut f = Feedback::new();
|
|
||||||
let node = ValNode {
|
let node = ValNode {
|
||||||
body: parse_body_maybe(call.body, state, &mut f),
|
body: call.body.map(|s| s.v),
|
||||||
};
|
};
|
||||||
Pass::node(node, f)
|
Pass::node(node, Feedback::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -15,9 +15,9 @@ pub type CallParser = dyn Fn(FuncCall, &ParseState) -> Pass<SyntaxNode>;
|
|||||||
|
|
||||||
/// An invocation of a function.
|
/// An invocation of a function.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct FuncCall<'s> {
|
pub struct FuncCall {
|
||||||
pub header: FuncHeader,
|
pub header: FuncHeader,
|
||||||
pub body: FuncBody<'s>,
|
pub body: FuncBody,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The parsed header of a function (everything in the first set of brackets).
|
/// The parsed header of a function (everything in the first set of brackets).
|
||||||
@ -29,7 +29,7 @@ pub struct FuncHeader {
|
|||||||
|
|
||||||
/// The body of a function as a raw spanned string containing what's inside of
|
/// The body of a function as a raw spanned string containing what's inside of
|
||||||
/// the brackets.
|
/// the brackets.
|
||||||
pub type FuncBody<'s> = Option<Spanned<&'s str>>;
|
pub type FuncBody = Option<Spanned<SyntaxTree>>;
|
||||||
|
|
||||||
/// The positional and keyword arguments passed to a function.
|
/// The positional and keyword arguments passed to a function.
|
||||||
#[derive(Debug, Default, Clone, PartialEq)]
|
#[derive(Debug, Default, Clone, PartialEq)]
|
||||||
@ -196,9 +196,17 @@ impl<'s> FuncParser<'s> {
|
|||||||
(parser, header)
|
(parser, header)
|
||||||
};
|
};
|
||||||
|
|
||||||
let call = FuncCall { header, body: self.body };
|
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
|
||||||
|
}));
|
||||||
|
|
||||||
|
let call = FuncCall { header, body };
|
||||||
|
|
||||||
let parsed = parser(call, self.state);
|
let parsed = parser(call, self.state);
|
||||||
self.feedback.extend(parsed.feedback);
|
self.feedback.extend(parsed.feedback);
|
||||||
|
|
||||||
Pass::new(parsed.output, self.feedback)
|
Pass::new(parsed.output, self.feedback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,13 +58,12 @@ macro_rules! span_item {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_func(call: FuncCall, state: &ParseState) -> Pass<SyntaxNode> {
|
pub fn debug_func(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> {
|
||||||
let mut f = Feedback::new();
|
|
||||||
let node = DebugNode {
|
let node = DebugNode {
|
||||||
header: call.header,
|
header: call.header,
|
||||||
body: parse_body_maybe(call.body, state, &mut f),
|
body: call.body.map(|s| s.v),
|
||||||
};
|
};
|
||||||
Pass::node(node, f)
|
Pass::node(node, Feedback::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user