mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
A few small improvements ♻
This commit is contained in:
parent
2b6ccd8248
commit
8cad78481c
@ -104,16 +104,16 @@ impl Display for Level {
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
|
||||
pub enum Deco {
|
||||
/// Emphasized text.
|
||||
Emph,
|
||||
/// Strong text.
|
||||
Strong,
|
||||
/// Emphasized text.
|
||||
Emph,
|
||||
/// A valid, successfully resolved name.
|
||||
Resolved,
|
||||
/// An invalid, unresolved name.
|
||||
Unresolved,
|
||||
/// A key in a dictionary.
|
||||
DictKey,
|
||||
/// A name in a dictionary or argument list.
|
||||
Name,
|
||||
}
|
||||
|
||||
/// Construct a diagnostic with [`Error`](Level::Error) level.
|
||||
|
@ -4,7 +4,7 @@ use std::mem;
|
||||
|
||||
use super::{Conv, EvalContext, RefKey, TryFromValue, Value, ValueDict};
|
||||
use crate::diag::Diag;
|
||||
use crate::syntax::{Span, SpanVec, SpanWith, Spanned};
|
||||
use crate::syntax::{Span, SpanVec, Spanned, WithSpan};
|
||||
|
||||
/// A wrapper around a dictionary value that simplifies argument parsing in
|
||||
/// functions.
|
||||
@ -23,7 +23,11 @@ impl Args {
|
||||
{
|
||||
self.0.v.remove(key).and_then(|entry| {
|
||||
let span = entry.value.span;
|
||||
conv_diag(T::try_from_value(entry.value), &mut ctx.f.diags, span)
|
||||
conv_diag(
|
||||
T::try_from_value(entry.value),
|
||||
&mut ctx.feedback.diags,
|
||||
span,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@ -41,9 +45,13 @@ impl Args {
|
||||
{
|
||||
if let Some(entry) = self.0.v.remove(key) {
|
||||
let span = entry.value.span;
|
||||
conv_diag(T::try_from_value(entry.value), &mut ctx.f.diags, span)
|
||||
conv_diag(
|
||||
T::try_from_value(entry.value),
|
||||
&mut ctx.feedback.diags,
|
||||
span,
|
||||
)
|
||||
} else {
|
||||
ctx.f.diags.push(error!(self.0.span, "missing argument: {}", name));
|
||||
ctx.diag(error!(self.0.span, "missing argument: {}", name));
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -122,11 +130,11 @@ fn conv_diag<T>(conv: Conv<T>, diags: &mut SpanVec<Diag>, span: Span) -> Option<
|
||||
match conv {
|
||||
Conv::Ok(t) => Some(t),
|
||||
Conv::Warn(t, warn) => {
|
||||
diags.push(warn.span_with(span));
|
||||
diags.push(warn.with_span(span));
|
||||
Some(t)
|
||||
}
|
||||
Conv::Err(_, err) => {
|
||||
diags.push(err.span_with(span));
|
||||
diags.push(err.with_span(span));
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -137,7 +145,7 @@ fn conv_put_back<T>(conv: Conv<T>, slot: &mut Spanned<Value>, span: Span) -> Opt
|
||||
Conv::Ok(t) => Some(t),
|
||||
Conv::Warn(t, _) => Some(t),
|
||||
Conv::Err(v, _) => {
|
||||
*slot = v.span_with(span);
|
||||
*slot = v.with_span(span);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
170
src/eval/mod.rs
170
src/eval/mod.rs
@ -48,7 +48,7 @@ pub struct EvalContext {
|
||||
/// The active evaluation state.
|
||||
pub state: State,
|
||||
/// The accumulated feedback.
|
||||
f: Feedback,
|
||||
feedback: Feedback,
|
||||
/// The finished page runs.
|
||||
runs: Vec<Pages>,
|
||||
/// The stack of logical groups (paragraphs and such).
|
||||
@ -71,24 +71,24 @@ impl EvalContext {
|
||||
groups: vec![],
|
||||
inner: vec![],
|
||||
runs: vec![],
|
||||
f: Feedback::new(),
|
||||
feedback: Feedback::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Finish evaluation and return the created document.
|
||||
pub fn finish(self) -> Pass<Document> {
|
||||
assert!(self.groups.is_empty(), "unfinished group");
|
||||
Pass::new(Document { runs: self.runs }, self.f)
|
||||
Pass::new(Document { runs: self.runs }, self.feedback)
|
||||
}
|
||||
|
||||
/// Add a diagnostic to the feedback.
|
||||
pub fn diag(&mut self, diag: Spanned<Diag>) {
|
||||
self.f.diags.push(diag);
|
||||
self.feedback.diags.push(diag);
|
||||
}
|
||||
|
||||
/// Add a decoration to the feedback.
|
||||
pub fn deco(&mut self, deco: Spanned<Deco>) {
|
||||
self.f.decos.push(deco);
|
||||
self.feedback.decos.push(deco);
|
||||
}
|
||||
|
||||
/// Push a layout node to the active group.
|
||||
@ -246,6 +246,23 @@ impl EvalContext {
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply a forced line break.
|
||||
pub fn apply_linebreak(&mut self) {
|
||||
self.end_par_group();
|
||||
self.start_par_group();
|
||||
}
|
||||
|
||||
/// Apply a forced paragraph break.
|
||||
pub fn apply_parbreak(&mut self) {
|
||||
self.end_par_group();
|
||||
let em = self.state.font.font_size();
|
||||
self.push(Spacing {
|
||||
amount: self.state.par.par_spacing.resolve(em),
|
||||
softness: Softness::Soft,
|
||||
});
|
||||
self.start_par_group();
|
||||
}
|
||||
|
||||
/// Construct a text node from the given string based on the active text
|
||||
/// state.
|
||||
pub fn make_text_node(&self, text: String) -> Text {
|
||||
@ -293,12 +310,12 @@ struct ParGroup {
|
||||
line_spacing: Length,
|
||||
}
|
||||
|
||||
/// Defines how items interact with surrounding items.
|
||||
/// Defines how an item interact with surrounding items.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum Softness {
|
||||
/// Soft items can be skipped in some circumstances.
|
||||
/// A soft item can be skipped in some circumstances.
|
||||
Soft,
|
||||
/// Hard items are always retained.
|
||||
/// A hard item is always retained.
|
||||
Hard,
|
||||
}
|
||||
|
||||
@ -310,24 +327,35 @@ pub trait Eval {
|
||||
type Output;
|
||||
|
||||
/// Evaluate the item to the output value.
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output;
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output;
|
||||
}
|
||||
|
||||
impl Eval for SynTree {
|
||||
impl<'a, T> Eval for &'a Box<Spanned<T>>
|
||||
where
|
||||
Spanned<&'a T>: Eval,
|
||||
{
|
||||
type Output = <Spanned<&'a T> as Eval>::Output;
|
||||
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
(**self).as_ref().eval(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for &[Spanned<SynNode>] {
|
||||
type Output = ();
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
for node in self {
|
||||
node.v.eval(ctx);
|
||||
node.as_ref().eval(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for SynNode {
|
||||
impl Eval for Spanned<&SynNode> {
|
||||
type Output = ();
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
match self {
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
match self.v {
|
||||
SynNode::Text(text) => {
|
||||
let node = ctx.make_text_node(text.clone());
|
||||
ctx.push(node);
|
||||
@ -340,53 +368,43 @@ impl Eval for SynNode {
|
||||
softness: Softness::Soft,
|
||||
});
|
||||
}
|
||||
|
||||
SynNode::Linebreak => {
|
||||
ctx.end_par_group();
|
||||
ctx.start_par_group();
|
||||
}
|
||||
|
||||
SynNode::Parbreak => {
|
||||
ctx.end_par_group();
|
||||
let em = ctx.state.font.font_size();
|
||||
ctx.push(Spacing {
|
||||
amount: ctx.state.par.par_spacing.resolve(em),
|
||||
softness: Softness::Soft,
|
||||
});
|
||||
ctx.start_par_group();
|
||||
}
|
||||
SynNode::Linebreak => ctx.apply_linebreak(),
|
||||
SynNode::Parbreak => ctx.apply_parbreak(),
|
||||
|
||||
SynNode::Strong => ctx.state.font.strong ^= true,
|
||||
SynNode::Emph => ctx.state.font.emph ^= true,
|
||||
|
||||
SynNode::Heading(heading) => heading.eval(ctx),
|
||||
SynNode::Raw(raw) => raw.eval(ctx),
|
||||
SynNode::Heading(heading) => heading.with_span(self.span).eval(ctx),
|
||||
SynNode::Raw(raw) => raw.with_span(self.span).eval(ctx),
|
||||
|
||||
SynNode::Expr(expr) => expr.eval(ctx).eval(ctx),
|
||||
SynNode::Expr(expr) => {
|
||||
let value = expr.with_span(self.span).eval(ctx);
|
||||
value.eval(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for NodeHeading {
|
||||
impl Eval for Spanned<&NodeHeading> {
|
||||
type Output = ();
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
let prev = ctx.state.clone();
|
||||
let upscale = 1.5 - 0.1 * self.level.v as f64;
|
||||
let upscale = 1.5 - 0.1 * self.v.level.v as f64;
|
||||
ctx.state.font.scale *= upscale;
|
||||
ctx.state.font.strong = true;
|
||||
|
||||
self.contents.eval(ctx);
|
||||
SynNode::Parbreak.eval(ctx);
|
||||
self.v.contents.eval(ctx);
|
||||
ctx.apply_parbreak();
|
||||
|
||||
ctx.state = prev;
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for NodeRaw {
|
||||
impl Eval for Spanned<&NodeRaw> {
|
||||
type Output = ();
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
let prev = Rc::clone(&ctx.state.font.families);
|
||||
let families = Rc::make_mut(&mut ctx.state.font.families);
|
||||
families.list.insert(0, "monospace".to_string());
|
||||
@ -396,7 +414,7 @@ impl Eval for NodeRaw {
|
||||
let line_spacing = ctx.state.par.line_spacing.resolve(em);
|
||||
|
||||
let mut children = vec![];
|
||||
for line in &self.lines {
|
||||
for line in &self.v.lines {
|
||||
children.push(LayoutNode::Text(ctx.make_text_node(line.clone())));
|
||||
children.push(LayoutNode::Spacing(Spacing {
|
||||
amount: line_spacing,
|
||||
@ -415,24 +433,24 @@ impl Eval for NodeRaw {
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for Expr {
|
||||
impl Eval for Spanned<&Expr> {
|
||||
type Output = Value;
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
match self {
|
||||
Self::Lit(lit) => lit.eval(ctx),
|
||||
Self::Call(call) => call.eval(ctx),
|
||||
Self::Unary(unary) => unary.eval(ctx),
|
||||
Self::Binary(binary) => binary.eval(ctx),
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
match self.v {
|
||||
Expr::Lit(lit) => lit.with_span(self.span).eval(ctx),
|
||||
Expr::Call(call) => call.with_span(self.span).eval(ctx),
|
||||
Expr::Unary(unary) => unary.with_span(self.span).eval(ctx),
|
||||
Expr::Binary(binary) => binary.with_span(self.span).eval(ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for Lit {
|
||||
impl Eval for Spanned<&Lit> {
|
||||
type Output = Value;
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
match *self {
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
match *self.v {
|
||||
Lit::Ident(ref v) => Value::Ident(v.clone()),
|
||||
Lit::Bool(v) => Value::Bool(v),
|
||||
Lit::Int(v) => Value::Int(v),
|
||||
@ -441,20 +459,20 @@ impl Eval for Lit {
|
||||
Lit::Percent(v) => Value::Relative(Relative::new(v / 100.0)),
|
||||
Lit::Color(v) => Value::Color(Color::Rgba(v)),
|
||||
Lit::Str(ref v) => Value::Str(v.clone()),
|
||||
Lit::Dict(ref v) => Value::Dict(v.eval(ctx)),
|
||||
Lit::Dict(ref v) => Value::Dict(v.with_span(self.span).eval(ctx)),
|
||||
Lit::Content(ref v) => Value::Content(v.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Eval for LitDict {
|
||||
impl Eval for Spanned<&LitDict> {
|
||||
type Output = ValueDict;
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
let mut dict = ValueDict::new();
|
||||
|
||||
for entry in &self.0 {
|
||||
let val = entry.expr.v.eval(ctx);
|
||||
let spanned = val.span_with(entry.expr.span);
|
||||
for entry in &self.v.0 {
|
||||
let val = entry.expr.as_ref().eval(ctx);
|
||||
let spanned = val.with_span(entry.expr.span);
|
||||
if let Some(key) = &entry.key {
|
||||
dict.insert(&key.v, SpannedEntry::new(key.span, spanned));
|
||||
} else {
|
||||
@ -466,58 +484,58 @@ impl Eval for LitDict {
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for ExprCall {
|
||||
impl Eval for Spanned<&ExprCall> {
|
||||
type Output = Value;
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
let name = &self.name.v;
|
||||
let span = self.name.span;
|
||||
let dict = self.args.v.eval(ctx);
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
let name = &self.v.name.v;
|
||||
let span = self.v.name.span;
|
||||
let dict = self.v.args.as_ref().eval(ctx);
|
||||
|
||||
if let Some(func) = ctx.state.scope.get(name) {
|
||||
let args = Args(dict.span_with(self.args.span));
|
||||
ctx.f.decos.push(Deco::Resolved.span_with(span));
|
||||
let args = Args(dict.with_span(self.v.args.span));
|
||||
ctx.feedback.decos.push(Deco::Resolved.with_span(span));
|
||||
(func.clone())(args, ctx)
|
||||
} else {
|
||||
if !name.is_empty() {
|
||||
ctx.diag(error!(span, "unknown function"));
|
||||
ctx.f.decos.push(Deco::Unresolved.span_with(span));
|
||||
ctx.feedback.decos.push(Deco::Unresolved.with_span(span));
|
||||
}
|
||||
Value::Dict(dict)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for ExprUnary {
|
||||
impl Eval for Spanned<&ExprUnary> {
|
||||
type Output = Value;
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
let value = self.expr.v.eval(ctx);
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
let value = self.v.expr.eval(ctx);
|
||||
|
||||
if let Value::Error = value {
|
||||
return Value::Error;
|
||||
}
|
||||
|
||||
let span = self.op.span.join(self.expr.span);
|
||||
match self.op.v {
|
||||
let span = self.v.op.span.join(self.v.expr.span);
|
||||
match self.v.op.v {
|
||||
UnOp::Neg => neg(ctx, span, value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for ExprBinary {
|
||||
impl Eval for Spanned<&ExprBinary> {
|
||||
type Output = Value;
|
||||
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
let lhs = self.lhs.v.eval(ctx);
|
||||
let rhs = self.rhs.v.eval(ctx);
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
let lhs = self.v.lhs.eval(ctx);
|
||||
let rhs = self.v.rhs.eval(ctx);
|
||||
|
||||
if lhs == Value::Error || rhs == Value::Error {
|
||||
return Value::Error;
|
||||
}
|
||||
|
||||
let span = self.lhs.span.join(self.rhs.span);
|
||||
match self.op.v {
|
||||
let span = self.v.lhs.span.join(self.v.rhs.span);
|
||||
match self.v.op.v {
|
||||
BinOp::Add => add(ctx, span, lhs, rhs),
|
||||
BinOp::Sub => sub(ctx, span, lhs, rhs),
|
||||
BinOp::Mul => mul(ctx, span, lhs, rhs),
|
||||
|
@ -11,7 +11,7 @@ use crate::color::Color;
|
||||
use crate::diag::Diag;
|
||||
use crate::geom::{Dir, Length, Linear, Relative};
|
||||
use crate::paper::Paper;
|
||||
use crate::syntax::{Ident, SpanWith, Spanned, SynTree};
|
||||
use crate::syntax::{Ident, Spanned, SynTree, WithSpan};
|
||||
|
||||
/// A computational value.
|
||||
#[derive(Clone, PartialEq)]
|
||||
@ -69,11 +69,11 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for Value {
|
||||
impl Eval for &Value {
|
||||
type Output = ();
|
||||
|
||||
/// Evaluate everything contained in this value.
|
||||
fn eval(&self, ctx: &mut EvalContext) -> Self::Output {
|
||||
fn eval(self, ctx: &mut EvalContext) -> Self::Output {
|
||||
match self {
|
||||
// Don't print out none values.
|
||||
Value::None => {}
|
||||
@ -206,7 +206,7 @@ impl<T> Conv<T> {
|
||||
impl<T: TryFromValue> TryFromValue for Spanned<T> {
|
||||
fn try_from_value(value: Spanned<Value>) -> Conv<Self> {
|
||||
let span = value.span;
|
||||
T::try_from_value(value).map(|v| v.span_with(span))
|
||||
T::try_from_value(value).map(|v| v.with_span(span))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
use std::any::Any;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -19,7 +18,10 @@ pub enum LayoutNode {
|
||||
|
||||
impl LayoutNode {
|
||||
/// Create a new dynamic node.
|
||||
pub fn dynamic<T: DynNode>(inner: T) -> Self {
|
||||
pub fn dynamic<T>(inner: T) -> Self
|
||||
where
|
||||
T: Layout + Debug + Clone + PartialEq + 'static,
|
||||
{
|
||||
Self::Dyn(Dynamic::new(inner))
|
||||
}
|
||||
}
|
||||
@ -44,33 +46,22 @@ impl Debug for LayoutNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around a boxed node trait object.
|
||||
///
|
||||
/// _Note_: This is needed because the compiler can't `derive(PartialEq)` for
|
||||
/// [`LayoutNode`] when directly putting the `Box` in there, see the
|
||||
/// [Rust Issue].
|
||||
///
|
||||
/// [Rust Issue]: https://github.com/rust-lang/rust/issues/31740
|
||||
pub struct Dynamic(pub Box<dyn DynNode>);
|
||||
/// A wrapper around a dynamic layouting node.
|
||||
pub struct Dynamic(Box<dyn Bounds>);
|
||||
|
||||
impl Dynamic {
|
||||
/// Wrap a type implementing `DynNode`.
|
||||
pub fn new<T: DynNode>(inner: T) -> Self {
|
||||
/// Create a new instance from any node that satisifies the required bounds.
|
||||
pub fn new<T>(inner: T) -> Self
|
||||
where
|
||||
T: Layout + Debug + Clone + PartialEq + 'static,
|
||||
{
|
||||
Self(Box::new(inner))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Dynamic {
|
||||
type Target = dyn DynNode;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Dynamic {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
impl Layout for Dynamic {
|
||||
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted {
|
||||
self.0.layout(ctx, areas)
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,41 +77,33 @@ impl PartialEq for Dynamic {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Dynamic {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Dynamic> for LayoutNode {
|
||||
fn from(dynamic: Dynamic) -> Self {
|
||||
Self::Dyn(dynamic)
|
||||
}
|
||||
}
|
||||
|
||||
/// A dynamic node, which can implement custom layouting behaviour.
|
||||
///
|
||||
/// This trait just combines the requirements for types to qualify as dynamic
|
||||
/// nodes. The interesting part happens in the inherited trait [`Layout`].
|
||||
///
|
||||
/// The trait itself also contains three helper methods to make `Box<dyn
|
||||
/// DynNode>` able to implement `Clone` and `PartialEq`. However, these are
|
||||
/// automatically provided by a blanket impl as long as the type in question
|
||||
/// implements[`Layout`], `Debug`, `PartialEq`, `Clone` and is `'static`.
|
||||
pub trait DynNode: Debug + Layout + 'static {
|
||||
/// Convert into a `dyn Any` to enable downcasting.
|
||||
trait Bounds: Layout + Debug + 'static {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
/// Check for equality with another trait object.
|
||||
fn dyn_eq(&self, other: &dyn DynNode) -> bool;
|
||||
|
||||
/// Clone into a trait object.
|
||||
fn dyn_clone(&self) -> Box<dyn DynNode>;
|
||||
fn dyn_eq(&self, other: &dyn Bounds) -> bool;
|
||||
fn dyn_clone(&self) -> Box<dyn Bounds>;
|
||||
}
|
||||
|
||||
impl<T> DynNode for T
|
||||
impl<T> Bounds for T
|
||||
where
|
||||
T: Debug + Layout + PartialEq + Clone + 'static,
|
||||
T: Layout + Debug + PartialEq + Clone + 'static,
|
||||
{
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn dyn_eq(&self, other: &dyn DynNode) -> bool {
|
||||
fn dyn_eq(&self, other: &dyn Bounds) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||
self == other
|
||||
} else {
|
||||
@ -128,7 +111,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn dyn_clone(&self) -> Box<dyn DynNode> {
|
||||
fn dyn_clone(&self) -> Box<dyn Bounds> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ pub fn font(mut args: Args, ctx: &mut EvalContext) -> Value {
|
||||
|
||||
try_from_match!(FamilyList["family or list of families"] @ span:
|
||||
Value::Str(v) => Self(vec![v.to_lowercase()]),
|
||||
Value::Dict(v) => Self(Args(v.span_with(span))
|
||||
Value::Dict(v) => Self(Args(v.with_span(span))
|
||||
.find_all::<StringLike>()
|
||||
.map(|s| s.to_lowercase())
|
||||
.collect()
|
||||
|
@ -123,10 +123,9 @@ fn heading(p: &mut Parser) -> NodeHeading {
|
||||
|
||||
/// Handle a raw block.
|
||||
fn raw(p: &mut Parser, token: TokenRaw) -> NodeRaw {
|
||||
let span = p.peek_span();
|
||||
let raw = resolve::resolve_raw(token.text, token.backticks);
|
||||
if !token.terminated {
|
||||
p.diag(error!(span.end, "expected backtick(s)"));
|
||||
p.diag(error!(p.peek_span().end, "expected backtick(s)"));
|
||||
}
|
||||
raw
|
||||
}
|
||||
@ -193,7 +192,7 @@ fn bracket_call(p: &mut Parser) -> ExprCall {
|
||||
while let Some(mut top) = outer.pop() {
|
||||
let span = inner.span;
|
||||
let node = inner.map(|c| SynNode::Expr(Expr::Call(c)));
|
||||
let expr = Expr::Lit(Lit::Content(vec![node])).span_with(span);
|
||||
let expr = Expr::Lit(Lit::Content(vec![node])).with_span(span);
|
||||
top.v.args.v.0.push(LitDictEntry { key: None, expr });
|
||||
inner = top;
|
||||
}
|
||||
@ -213,7 +212,7 @@ fn bracket_subheader(p: &mut Parser) -> ExprCall {
|
||||
} else {
|
||||
p.diag_expected(what);
|
||||
}
|
||||
Ident(String::new()).span_with(start)
|
||||
Ident(String::new()).with_span(start)
|
||||
});
|
||||
|
||||
let args = p.span(|p| dict_contents(p).0);
|
||||
@ -247,7 +246,7 @@ fn dict_contents(p: &mut Parser) -> (LitDict, bool) {
|
||||
|
||||
if let Some(key) = &entry.key {
|
||||
comma_and_keyless = false;
|
||||
p.deco(Deco::DictKey.span_with(key.span));
|
||||
p.deco(Deco::Name.with_span(key.span));
|
||||
}
|
||||
|
||||
dict.0.push(entry);
|
||||
@ -286,7 +285,7 @@ fn dict_entry(p: &mut Parser) -> Option<LitDictEntry> {
|
||||
expr: {
|
||||
let start = ident.span.start;
|
||||
let call = paren_call(p, ident);
|
||||
Expr::Call(call).span_with(start .. p.last_end())
|
||||
Expr::Call(call).with_span(start .. p.last_end())
|
||||
},
|
||||
}),
|
||||
|
||||
@ -335,7 +334,7 @@ fn binops(
|
||||
op,
|
||||
rhs: Box::new(rhs),
|
||||
});
|
||||
lhs = expr.span_with(span);
|
||||
lhs = expr.with_span(span);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -361,36 +360,32 @@ fn factor(p: &mut Parser) -> Option<Expr> {
|
||||
|
||||
/// Parse a value.
|
||||
fn value(p: &mut Parser) -> Option<Expr> {
|
||||
let start = p.next_start();
|
||||
Some(match p.eat() {
|
||||
let expr = match p.peek() {
|
||||
// Bracketed function call.
|
||||
Some(Token::LeftBracket) => {
|
||||
p.jump(start);
|
||||
let node = p.span(|p| SynNode::Expr(Expr::Call(bracket_call(p))));
|
||||
Expr::Lit(Lit::Content(vec![node]))
|
||||
return Some(Expr::Lit(Lit::Content(vec![node])));
|
||||
}
|
||||
|
||||
// Content expression.
|
||||
Some(Token::LeftBrace) => {
|
||||
p.jump(start);
|
||||
Expr::Lit(Lit::Content(content(p)))
|
||||
return Some(Expr::Lit(Lit::Content(content(p))));
|
||||
}
|
||||
|
||||
// Dictionary or just a parenthesized expression.
|
||||
Some(Token::LeftParen) => {
|
||||
p.jump(start);
|
||||
parenthesized(p)
|
||||
return Some(parenthesized(p));
|
||||
}
|
||||
|
||||
// Function or just ident.
|
||||
Some(Token::Ident(id)) => {
|
||||
p.eat();
|
||||
let ident = Ident(id.into());
|
||||
let after = p.last_end();
|
||||
if p.peek() == Some(Token::LeftParen) {
|
||||
let name = ident.span_with(start .. after);
|
||||
Expr::Call(paren_call(p, name))
|
||||
let name = ident.with_span(p.peek_span());
|
||||
return Some(Expr::Call(paren_call(p, name)));
|
||||
} else {
|
||||
Expr::Lit(Lit::Ident(ident))
|
||||
return Some(Expr::Lit(Lit::Ident(ident)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,16 +395,17 @@ fn value(p: &mut Parser) -> Option<Expr> {
|
||||
Some(Token::Float(f)) => Expr::Lit(Lit::Float(f)),
|
||||
Some(Token::Length(val, unit)) => Expr::Lit(Lit::Length(val, unit)),
|
||||
Some(Token::Percent(p)) => Expr::Lit(Lit::Percent(p)),
|
||||
Some(Token::Hex(hex)) => Expr::Lit(Lit::Color(color(p, hex, start))),
|
||||
Some(Token::Hex(hex)) => Expr::Lit(Lit::Color(color(p, hex))),
|
||||
Some(Token::Str(token)) => Expr::Lit(Lit::Str(str(p, token))),
|
||||
|
||||
// No value.
|
||||
_ => {
|
||||
p.jump(start);
|
||||
p.diag_expected("expression");
|
||||
return None;
|
||||
}
|
||||
})
|
||||
};
|
||||
p.eat();
|
||||
Some(expr)
|
||||
}
|
||||
|
||||
// Parse a content value: `{...}`.
|
||||
@ -444,10 +440,10 @@ fn ident(p: &mut Parser) -> Option<Ident> {
|
||||
}
|
||||
|
||||
/// Parse a color.
|
||||
fn color(p: &mut Parser, hex: &str, start: Pos) -> RgbaColor {
|
||||
fn color(p: &mut Parser, hex: &str) -> RgbaColor {
|
||||
RgbaColor::from_str(hex).unwrap_or_else(|_| {
|
||||
// Replace color with black.
|
||||
p.diag(error!(start .. p.last_end(), "invalid color"));
|
||||
p.diag(error!(p.peek_span(), "invalid color"));
|
||||
RgbaColor::new(0, 0, 0, 255)
|
||||
})
|
||||
}
|
||||
@ -455,7 +451,7 @@ fn color(p: &mut Parser, hex: &str, start: Pos) -> RgbaColor {
|
||||
/// Parse a string.
|
||||
fn str(p: &mut Parser, token: TokenStr) -> String {
|
||||
if !token.terminated {
|
||||
p.diag_expected_at("quote", p.last_end());
|
||||
p.diag_expected_at("quote", p.peek_span().end);
|
||||
}
|
||||
|
||||
resolve::resolve_string(token.string)
|
||||
|
@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Formatter};
|
||||
use super::{Scanner, TokenMode, Tokens};
|
||||
use crate::diag::Diag;
|
||||
use crate::diag::{Deco, Feedback};
|
||||
use crate::syntax::{Pos, Span, SpanWith, Spanned, Token};
|
||||
use crate::syntax::{Pos, Span, Spanned, Token, WithSpan};
|
||||
|
||||
/// A convenient token-based parser.
|
||||
pub struct Parser<'s> {
|
||||
@ -23,7 +23,7 @@ pub struct Parser<'s> {
|
||||
/// The stack of open groups.
|
||||
groups: Vec<Group>,
|
||||
/// Accumulated feedback.
|
||||
f: Feedback,
|
||||
feedback: Feedback,
|
||||
}
|
||||
|
||||
impl<'s> Parser<'s> {
|
||||
@ -39,18 +39,18 @@ impl<'s> Parser<'s> {
|
||||
last_end: Pos::ZERO,
|
||||
modes: vec![],
|
||||
groups: vec![],
|
||||
f: Feedback::new(),
|
||||
feedback: Feedback::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Finish parsing and return the accumulated feedback.
|
||||
pub fn finish(self) -> Feedback {
|
||||
self.f
|
||||
self.feedback
|
||||
}
|
||||
|
||||
/// Add a diagnostic to the feedback.
|
||||
pub fn diag(&mut self, diag: Spanned<Diag>) {
|
||||
self.f.diags.push(diag);
|
||||
self.feedback.diags.push(diag);
|
||||
}
|
||||
|
||||
/// Eat the next token and add a diagnostic that it is not the expected
|
||||
@ -89,7 +89,7 @@ impl<'s> Parser<'s> {
|
||||
|
||||
/// Add a decoration to the feedback.
|
||||
pub fn deco(&mut self, deco: Spanned<Deco>) {
|
||||
self.f.decos.push(deco);
|
||||
self.feedback.decos.push(deco);
|
||||
}
|
||||
|
||||
/// Update the token mode and push the previous mode onto a stack.
|
||||
@ -162,7 +162,7 @@ impl<'s> Parser<'s> {
|
||||
let start = self.next_start;
|
||||
let output = f(self);
|
||||
let end = self.last_end;
|
||||
output.span_with(start .. end)
|
||||
output.with_span(start .. end)
|
||||
}
|
||||
|
||||
/// A version of [`span`](Self::span) that works better with options.
|
||||
@ -251,34 +251,11 @@ impl<'s> Parser<'s> {
|
||||
self.last_end
|
||||
}
|
||||
|
||||
/// Jump to a position in the source string.
|
||||
pub fn jump(&mut self, pos: Pos) {
|
||||
self.tokens.jump(pos);
|
||||
self.bump();
|
||||
}
|
||||
|
||||
/// Slice a part out of the source string.
|
||||
pub fn get(&self, span: impl Into<Span>) -> &'s str {
|
||||
self.tokens.scanner().get(span.into().to_range())
|
||||
}
|
||||
|
||||
/// The full source string up to the end of the last token.
|
||||
pub fn eaten(&self) -> &'s str {
|
||||
self.tokens.scanner().get(.. self.last_end.to_usize())
|
||||
}
|
||||
|
||||
/// The source string from `start` to the end of the last token.
|
||||
pub fn eaten_from(&self, start: Pos) -> &'s str {
|
||||
self.tokens
|
||||
.scanner()
|
||||
.get(start.to_usize() .. self.last_end.to_usize())
|
||||
}
|
||||
|
||||
/// The remaining source string after the start of the next token.
|
||||
pub fn rest(&self) -> &'s str {
|
||||
self.tokens.scanner().get(self.next_start.to_usize() ..)
|
||||
}
|
||||
|
||||
/// The underlying scanner.
|
||||
pub fn scanner(&self) -> Scanner<'s> {
|
||||
let mut scanner = self.tokens.scanner().clone();
|
||||
@ -325,7 +302,8 @@ impl<'s> Parser<'s> {
|
||||
|
||||
impl Debug for Parser<'_> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "Parser({}|{})", self.eaten(), self.rest())
|
||||
let s = self.scanner();
|
||||
write!(f, "Parser({}|{})", s.eaten(), s.rest())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,11 +102,6 @@ impl<'s> Scanner<'s> {
|
||||
self.peek().map(f).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Whether the end of the source string is reached.
|
||||
pub fn eof(&self) -> bool {
|
||||
self.index == self.src.len()
|
||||
}
|
||||
|
||||
/// The previous index in the source string.
|
||||
pub fn last_index(&self) -> usize {
|
||||
self.src[.. self.index]
|
||||
@ -126,11 +121,6 @@ impl<'s> Scanner<'s> {
|
||||
self.index = index;
|
||||
}
|
||||
|
||||
/// The full source string.
|
||||
pub fn src(&self) -> &'s str {
|
||||
self.src
|
||||
}
|
||||
|
||||
/// Slice a part out of the source string.
|
||||
pub fn get<I>(&self, index: I) -> &'s str
|
||||
where
|
||||
|
@ -46,11 +46,6 @@ impl<'s> Tokens<'s> {
|
||||
self.s.index().into()
|
||||
}
|
||||
|
||||
/// Jump to a position in the source string.
|
||||
pub fn jump(&mut self, pos: Pos) {
|
||||
self.s.jump(pos.to_usize());
|
||||
}
|
||||
|
||||
/// The underlying scanner.
|
||||
pub fn scanner(&self) -> &Scanner<'s> {
|
||||
&self.s
|
||||
@ -325,7 +320,9 @@ impl<'s> Tokens<'s> {
|
||||
}
|
||||
|
||||
// Read the suffix.
|
||||
self.s.eat_while(|c| c == '%' || c.is_ascii_alphanumeric());
|
||||
if !self.s.eat_if('%') {
|
||||
self.s.eat_while(|c| c.is_ascii_alphanumeric());
|
||||
}
|
||||
|
||||
// Parse into one of the suitable types.
|
||||
let string = self.s.eaten_from(start);
|
||||
@ -790,5 +787,7 @@ mod tests {
|
||||
|
||||
// Test invalid number suffixes.
|
||||
t!(Header[" /"]: "1foo" => Invalid("1foo"));
|
||||
t!(Header: "1p%" => Invalid("1p"), Invalid("%"));
|
||||
t!(Header: "1%%" => Percent(1.0), Invalid("%"));
|
||||
}
|
||||
}
|
||||
|
@ -7,5 +7,5 @@ pub use crate::geom::*;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::layout::LayoutNode;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::syntax::{Span, SpanWith, Spanned, SynTree};
|
||||
pub use crate::syntax::{Span, Spanned, SynTree, WithSpan};
|
||||
pub use crate::{error, warning};
|
||||
|
@ -4,12 +4,13 @@ use std::ops::Deref;
|
||||
|
||||
use unicode_xid::UnicodeXID;
|
||||
|
||||
/// An identifier as defined by unicode with a few extra permissible characters.
|
||||
/// An Unicode identifier with a few extra permissible characters.
|
||||
///
|
||||
/// This is defined as in the [Unicode Standard], but allows additionally
|
||||
/// `-` and `_` as starting and continuing characters.
|
||||
/// In addition to what is specified in the [Unicode Standard][uax31], we allow:
|
||||
/// - `_` as a starting character,
|
||||
/// - `_` and `-` as continuing characters.
|
||||
///
|
||||
/// [Unicode Standard]: http://www.unicode.org/reports/tr31/
|
||||
/// [uax31]: http://www.unicode.org/reports/tr31/
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub struct Ident(pub String);
|
||||
|
||||
|
@ -30,16 +30,16 @@ pub enum SynNode {
|
||||
Expr(Expr),
|
||||
}
|
||||
|
||||
/// A section heading.
|
||||
/// A section heading: `# ...`.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct NodeHeading {
|
||||
/// The section depth (how many hashtags minus 1).
|
||||
/// The section depth (numer of hashtags minus 1).
|
||||
pub level: Spanned<u8>,
|
||||
/// The contents of the heading.
|
||||
pub contents: SynTree,
|
||||
}
|
||||
|
||||
/// A raw block, rendered in monospace with optional syntax highlighting.
|
||||
/// A raw block with optional syntax highlighting: `` `raw` ``.
|
||||
///
|
||||
/// Raw blocks start with an arbitrary number of backticks and end with the same
|
||||
/// number of backticks. If you want to include a sequence of backticks in a raw
|
||||
|
@ -12,14 +12,14 @@ thread_local! {
|
||||
}
|
||||
|
||||
/// Annotate a value with a span.
|
||||
pub trait SpanWith: Sized {
|
||||
pub trait WithSpan: Sized {
|
||||
/// Wraps `self` in a `Spanned` with the given span.
|
||||
fn span_with(self, span: impl Into<Span>) -> Spanned<Self> {
|
||||
fn with_span(self, span: impl Into<Span>) -> Spanned<Self> {
|
||||
Spanned::new(self, span)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SpanWith for T {}
|
||||
impl<T> WithSpan for T {}
|
||||
|
||||
/// Span offsetting.
|
||||
pub trait Offset {
|
||||
@ -81,7 +81,7 @@ impl<T> Spanned<Option<T>> {
|
||||
/// Swap the spanned and the option.
|
||||
pub fn transpose(self) -> Option<Spanned<T>> {
|
||||
let Spanned { v, span } = self;
|
||||
v.map(|v| v.span_with(span))
|
||||
v.map(|v| v.with_span(span))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ use typst::geom::{Length, Point, Sides, Size};
|
||||
use typst::layout::{BoxLayout, ImageElement, LayoutElement};
|
||||
use typst::parse::{LineMap, Scanner};
|
||||
use typst::shaping::Shaped;
|
||||
use typst::syntax::{Location, Pos, SpanVec, SpanWith, Spanned};
|
||||
use typst::syntax::{Location, Pos, SpanVec, Spanned, WithSpan};
|
||||
use typst::typeset;
|
||||
|
||||
const TYP_DIR: &str = "typ";
|
||||
@ -212,7 +212,7 @@ fn parse_metadata(src: &str, map: &LineMap) -> (SpanVec<Diag>, bool) {
|
||||
|
||||
let mut s = Scanner::new(rest);
|
||||
let (start, _, end) = (pos(&mut s, map), s.eat_assert('-'), pos(&mut s, map));
|
||||
diags.push(Diag::new(level, s.rest().trim()).span_with(start .. end));
|
||||
diags.push(Diag::new(level, s.rest().trim()).with_span(start .. end));
|
||||
}
|
||||
|
||||
diags.sort();
|
||||
@ -303,17 +303,17 @@ fn draw_text(canvas: &mut Canvas, pos: Point, env: &Env, shaped: &Shaped) {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_image(canvas: &mut Canvas, pos: Point, env: &Env, img: &ImageElement) {
|
||||
let buf = &env.resources.loaded::<ImageResource>(img.res).buf;
|
||||
fn draw_image(canvas: &mut Canvas, pos: Point, env: &Env, element: &ImageElement) {
|
||||
let img = &env.resources.loaded::<ImageResource>(element.res);
|
||||
|
||||
let mut pixmap = Pixmap::new(buf.width(), buf.height()).unwrap();
|
||||
for ((_, _, src), dest) in buf.pixels().zip(pixmap.pixels_mut()) {
|
||||
let mut pixmap = Pixmap::new(img.buf.width(), img.buf.height()).unwrap();
|
||||
for ((_, _, src), dest) in img.buf.pixels().zip(pixmap.pixels_mut()) {
|
||||
let Rgba([r, g, b, a]) = src;
|
||||
*dest = ColorU8::from_rgba(r, g, b, a).premultiply();
|
||||
}
|
||||
|
||||
let view_width = img.size.width.to_pt() as f32;
|
||||
let view_height = img.size.height.to_pt() as f32;
|
||||
let view_width = element.size.width.to_pt() as f32;
|
||||
let view_height = element.size.height.to_pt() as f32;
|
||||
|
||||
let x = pos.x.to_pt() as f32;
|
||||
let y = pos.y.to_pt() as f32;
|
||||
|
Loading…
x
Reference in New Issue
Block a user