mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Remove warnings from parsing and casting
This commit is contained in:
parent
982ce85976
commit
891e0c5fa6
@ -2,7 +2,7 @@ use std::fmt::{self, Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::{Cast, CastResult, EvalContext, Value};
|
||||
use super::{Cast, EvalContext, Value};
|
||||
use crate::eco::EcoString;
|
||||
use crate::syntax::{Span, Spanned};
|
||||
|
||||
@ -76,7 +76,7 @@ pub struct FuncArg {
|
||||
|
||||
impl FuncArgs {
|
||||
/// Find and consume the first castable positional argument.
|
||||
pub fn eat<T>(&mut self, ctx: &mut EvalContext) -> Option<T>
|
||||
pub fn eat<T>(&mut self) -> Option<T>
|
||||
where
|
||||
T: Cast<Spanned<Value>>,
|
||||
{
|
||||
@ -87,19 +87,12 @@ impl FuncArgs {
|
||||
}
|
||||
|
||||
let value = std::mem::replace(&mut slot.value, Spanned::zero(Value::None));
|
||||
let span = value.span;
|
||||
|
||||
match T::cast(value) {
|
||||
CastResult::Ok(t) => {
|
||||
Ok(t) => {
|
||||
self.items.remove(index);
|
||||
Some(t)
|
||||
}
|
||||
CastResult::Warn(t, m) => {
|
||||
self.items.remove(index);
|
||||
ctx.diag(warning!(span, "{}", m));
|
||||
Some(t)
|
||||
}
|
||||
CastResult::Err(value) => {
|
||||
Err(value) => {
|
||||
slot.value = value;
|
||||
None
|
||||
}
|
||||
@ -113,7 +106,7 @@ impl FuncArgs {
|
||||
where
|
||||
T: Cast<Spanned<Value>>,
|
||||
{
|
||||
let found = self.eat(ctx);
|
||||
let found = self.eat();
|
||||
if found.is_none() {
|
||||
ctx.diag(error!(self.span, "missing argument: {}", what));
|
||||
}
|
||||
@ -121,16 +114,11 @@ impl FuncArgs {
|
||||
}
|
||||
|
||||
/// Find, consume and collect all castable positional arguments.
|
||||
///
|
||||
/// This function returns a vector instead of an iterator because the
|
||||
/// iterator would require unique access to the context, rendering it rather
|
||||
/// unusable. If you need to process arguments one-by-one, you probably want
|
||||
/// to use a while-let loop together with [`eat()`](Self::eat).
|
||||
pub fn all<T>(&mut self, ctx: &mut EvalContext) -> Vec<T>
|
||||
pub fn all<T>(&mut self) -> impl Iterator<Item = T> + '_
|
||||
where
|
||||
T: Cast<Spanned<Value>>,
|
||||
{
|
||||
std::iter::from_fn(|| self.eat(ctx)).collect()
|
||||
std::iter::from_fn(move || self.eat())
|
||||
}
|
||||
|
||||
/// Cast and remove the value for the given named argument, producing an
|
||||
@ -148,12 +136,8 @@ impl FuncArgs {
|
||||
let span = value.span;
|
||||
|
||||
match T::cast(value) {
|
||||
CastResult::Ok(t) => Some(t),
|
||||
CastResult::Warn(t, m) => {
|
||||
ctx.diag(warning!(span, "{}", m));
|
||||
Some(t)
|
||||
}
|
||||
CastResult::Err(value) => {
|
||||
Ok(t) => Some(t),
|
||||
Err(value) => {
|
||||
ctx.diag(error!(
|
||||
span,
|
||||
"expected {}, found {}",
|
||||
|
@ -195,12 +195,8 @@ impl<'a> EvalContext<'a> {
|
||||
}
|
||||
|
||||
match T::cast(value) {
|
||||
CastResult::Ok(t) => Some(t),
|
||||
CastResult::Warn(t, m) => {
|
||||
self.diag(warning!(span, "{}", m));
|
||||
Some(t)
|
||||
}
|
||||
CastResult::Err(value) => {
|
||||
Ok(t) => Some(t),
|
||||
Err(value) => {
|
||||
self.diag(error!(
|
||||
span,
|
||||
"expected {}, found {}",
|
||||
|
@ -84,7 +84,7 @@ impl Value {
|
||||
}
|
||||
|
||||
/// Try to cast the value into a specific type.
|
||||
pub fn cast<T>(self) -> CastResult<T, Self>
|
||||
pub fn cast<T>(self) -> Result<T, Self>
|
||||
where
|
||||
T: Cast<Value>,
|
||||
{
|
||||
@ -236,28 +236,7 @@ where
|
||||
/// Cast from a value to a specific type.
|
||||
pub trait Cast<V>: Type + Sized {
|
||||
/// Try to cast the value into an instance of `Self`.
|
||||
fn cast(value: V) -> CastResult<Self, V>;
|
||||
}
|
||||
|
||||
/// The result of casting a value to a specific type.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum CastResult<T, V> {
|
||||
/// The value was cast successfully.
|
||||
Ok(T),
|
||||
/// The value was cast successfully, but with a warning message.
|
||||
Warn(T, String),
|
||||
/// The value could not be cast into the specified type.
|
||||
Err(V),
|
||||
}
|
||||
|
||||
impl<T, V> CastResult<T, V> {
|
||||
/// Access the conversion result, discarding a possibly existing warning.
|
||||
pub fn ok(self) -> Option<T> {
|
||||
match self {
|
||||
CastResult::Ok(t) | CastResult::Warn(t, _) => Some(t),
|
||||
CastResult::Err(_) => None,
|
||||
}
|
||||
}
|
||||
fn cast(value: V) -> Result<Self, V>;
|
||||
}
|
||||
|
||||
impl Type for Value {
|
||||
@ -265,8 +244,8 @@ impl Type for Value {
|
||||
}
|
||||
|
||||
impl Cast<Value> for Value {
|
||||
fn cast(value: Value) -> CastResult<Self, Value> {
|
||||
CastResult::Ok(value)
|
||||
fn cast(value: Value) -> Result<Self, Value> {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,12 +253,11 @@ impl<T> Cast<Spanned<Value>> for T
|
||||
where
|
||||
T: Cast<Value>,
|
||||
{
|
||||
fn cast(value: Spanned<Value>) -> CastResult<Self, Spanned<Value>> {
|
||||
fn cast(value: Spanned<Value>) -> Result<Self, Spanned<Value>> {
|
||||
let span = value.span;
|
||||
match T::cast(value.v) {
|
||||
CastResult::Ok(t) => CastResult::Ok(t),
|
||||
CastResult::Warn(t, m) => CastResult::Warn(t, m),
|
||||
CastResult::Err(v) => CastResult::Err(Spanned::new(v, span)),
|
||||
Ok(t) => Ok(t),
|
||||
Err(v) => Err(Spanned::new(v, span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -288,12 +266,11 @@ impl<T> Cast<Spanned<Value>> for Spanned<T>
|
||||
where
|
||||
T: Cast<Value>,
|
||||
{
|
||||
fn cast(value: Spanned<Value>) -> CastResult<Self, Spanned<Value>> {
|
||||
fn cast(value: Spanned<Value>) -> Result<Self, Spanned<Value>> {
|
||||
let span = value.span;
|
||||
match T::cast(value.v) {
|
||||
CastResult::Ok(t) => CastResult::Ok(Spanned::new(t, span)),
|
||||
CastResult::Warn(t, m) => CastResult::Warn(Spanned::new(t, span), m),
|
||||
CastResult::Err(v) => CastResult::Err(Spanned::new(v, span)),
|
||||
Ok(t) => Ok(Spanned::new(t, span)),
|
||||
Err(v) => Err(Spanned::new(v, span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -315,11 +292,11 @@ macro_rules! primitive {
|
||||
}
|
||||
|
||||
impl Cast<Value> for $type {
|
||||
fn cast(value: Value) -> CastResult<Self, Value> {
|
||||
fn cast(value: Value) -> Result<Self, Value> {
|
||||
match value {
|
||||
$variant(v) => CastResult::Ok(v),
|
||||
$($pattern => CastResult::Ok($out),)*
|
||||
v => CastResult::Err(v),
|
||||
$variant(v) => Ok(v),
|
||||
$($pattern => Ok($out),)*
|
||||
v => Err(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -426,26 +403,26 @@ macro_rules! castable {
|
||||
impl $crate::eval::Cast<$crate::eval::Value> for $type {
|
||||
fn cast(
|
||||
value: $crate::eval::Value,
|
||||
) -> $crate::eval::CastResult<Self, $crate::eval::Value> {
|
||||
) -> Result<Self, $crate::eval::Value> {
|
||||
use $crate::eval::*;
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
match value {
|
||||
$($pattern => CastResult::Ok($out),)*
|
||||
$($pattern => Ok($out),)*
|
||||
Value::Any(mut any) => {
|
||||
any = match any.downcast::<Self>() {
|
||||
Ok(t) => return CastResult::Ok(t),
|
||||
Ok(t) => return Ok(t),
|
||||
Err(any) => any,
|
||||
};
|
||||
|
||||
$(any = match any.downcast::<$anytype>() {
|
||||
Ok($anyvar) => return CastResult::Ok($anyout),
|
||||
Ok($anyvar) => return Ok($anyout),
|
||||
Err(any) => any,
|
||||
};)*
|
||||
|
||||
CastResult::Err(Value::Any(any))
|
||||
Err(Value::Any(any))
|
||||
},
|
||||
v => CastResult::Err(v),
|
||||
v => Err(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ pub fn rect(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let width = args.named(ctx, "width");
|
||||
let height = args.named(ctx, "height");
|
||||
let fill = args.named(ctx, "fill");
|
||||
let body = args.eat(ctx).unwrap_or_default();
|
||||
let body = args.eat().unwrap_or_default();
|
||||
rect_impl(width, height, None, fill, body)
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ pub fn square(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let width = length.or_else(|| args.named(ctx, "width"));
|
||||
let height = width.is_none().then(|| args.named(ctx, "height")).flatten();
|
||||
let fill = args.named(ctx, "fill");
|
||||
let body = args.eat(ctx).unwrap_or_default();
|
||||
let body = args.eat().unwrap_or_default();
|
||||
rect_impl(width, height, Some(N64::from(1.0)), fill, body)
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ pub fn ellipse(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let width = args.named(ctx, "width");
|
||||
let height = args.named(ctx, "height");
|
||||
let fill = args.named(ctx, "fill");
|
||||
let body = args.eat(ctx).unwrap_or_default();
|
||||
let body = args.eat().unwrap_or_default();
|
||||
ellipse_impl(width, height, None, fill, body)
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ pub fn circle(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let width = radius.or_else(|| args.named(ctx, "width"));
|
||||
let height = width.is_none().then(|| args.named(ctx, "height")).flatten();
|
||||
let fill = args.named(ctx, "fill");
|
||||
let body = args.eat(ctx).unwrap_or_default();
|
||||
let body = args.eat().unwrap_or_default();
|
||||
ellipse_impl(width, height, Some(N64::from(1.0)), fill, body)
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use crate::paper::{Paper, PaperClass};
|
||||
/// `page`: Configure pages.
|
||||
pub fn page(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let span = args.span;
|
||||
let paper = args.eat::<Spanned<EcoString>>(ctx).and_then(|name| {
|
||||
let paper = args.eat::<Spanned<EcoString>>().and_then(|name| {
|
||||
Paper::from_name(&name.v).or_else(|| {
|
||||
ctx.diag(error!(name.span, "invalid paper name"));
|
||||
None
|
||||
@ -104,8 +104,8 @@ fn spacing_impl(ctx: &mut EvalContext, args: &mut FuncArgs, axis: GenAxis) -> Va
|
||||
|
||||
/// `align`: Configure the alignment along the layouting axes.
|
||||
pub fn align(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let first = args.eat::<AlignValue>(ctx);
|
||||
let second = args.eat::<AlignValue>(ctx);
|
||||
let first = args.eat::<AlignValue>();
|
||||
let second = args.eat::<AlignValue>();
|
||||
let mut horizontal = args.named::<AlignValue>(ctx, "horizontal");
|
||||
let mut vertical = args.named::<AlignValue>(ctx, "vertical");
|
||||
let body = args.expect::<Template>(ctx, "body").unwrap_or_default();
|
||||
@ -207,7 +207,7 @@ castable! {
|
||||
pub fn boxed(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let width = args.named(ctx, "width");
|
||||
let height = args.named(ctx, "height");
|
||||
let body = args.eat(ctx).unwrap_or_default();
|
||||
let body = args.eat().unwrap_or_default();
|
||||
Value::template(move |ctx| {
|
||||
let child = ctx.exec_template_stack(&body).into();
|
||||
ctx.push_into_par(FixedNode { width, height, child });
|
||||
@ -216,7 +216,7 @@ pub fn boxed(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
|
||||
/// `block`: Place content in a block.
|
||||
pub fn block(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let body = args.eat(ctx).unwrap_or_default();
|
||||
let body = args.expect(ctx, "body").unwrap_or_default();
|
||||
Value::template(move |ctx| {
|
||||
let block = ctx.exec_template_stack(&body);
|
||||
ctx.push_into_stack(block);
|
||||
@ -225,7 +225,7 @@ pub fn block(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
|
||||
/// `pad`: Pad content at the sides.
|
||||
pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let all = args.eat(ctx);
|
||||
let all = args.eat();
|
||||
let left = args.named(ctx, "left");
|
||||
let top = args.named(ctx, "top");
|
||||
let right = args.named(ctx, "right");
|
||||
@ -248,7 +248,7 @@ pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
/// `stack`: Stack children along an axis.
|
||||
pub fn stack(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let dir = args.named::<Dir>(ctx, "dir").unwrap_or(Dir::TTB);
|
||||
let children = args.all(ctx);
|
||||
let children: Vec<_> = args.all().collect();
|
||||
|
||||
Value::template(move |ctx| {
|
||||
let children = children
|
||||
@ -271,15 +271,18 @@ pub fn stack(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
pub fn grid(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let columns = args.named::<Tracks>(ctx, "columns").unwrap_or_default();
|
||||
let rows = args.named::<Tracks>(ctx, "rows").unwrap_or_default();
|
||||
|
||||
let gutter_columns = args.named::<Tracks>(ctx, "gutter-columns");
|
||||
let gutter_rows = args.named::<Tracks>(ctx, "gutter-rows");
|
||||
let gutter = args
|
||||
.named::<Linear>(ctx, "gutter")
|
||||
.map(|v| vec![TrackSizing::Linear(v)])
|
||||
.unwrap_or_default();
|
||||
let gutter_columns = args.named::<Tracks>(ctx, "gutter-columns");
|
||||
let gutter_rows = args.named::<Tracks>(ctx, "gutter-rows");
|
||||
|
||||
let column_dir = args.named(ctx, "column-dir");
|
||||
let row_dir = args.named(ctx, "row-dir");
|
||||
let children = args.all(ctx);
|
||||
|
||||
let children: Vec<_> = args.all().collect();
|
||||
|
||||
Value::template(move |ctx| {
|
||||
let children = children
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::exec::{FontState, LineState};
|
||||
use crate::font::{FontStretch, FontStyle, FontWeight};
|
||||
use crate::layout::Paint;
|
||||
@ -6,14 +8,14 @@ use super::*;
|
||||
|
||||
/// `font`: Configure the font.
|
||||
pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let families = args.all(ctx);
|
||||
let families: Vec<_> = args.all().collect();
|
||||
let list = if families.is_empty() {
|
||||
args.named(ctx, "family")
|
||||
} else {
|
||||
Some(FontDef(families))
|
||||
};
|
||||
|
||||
let size = args.eat(ctx).or_else(|| args.named::<Linear>(ctx, "size"));
|
||||
let size = args.eat().or_else(|| args.named::<Linear>(ctx, "size"));
|
||||
let style = args.named(ctx, "style");
|
||||
let weight = args.named(ctx, "weight");
|
||||
let stretch = args.named(ctx, "stretch");
|
||||
@ -116,42 +118,13 @@ castable! {
|
||||
castable! {
|
||||
FontWeight: "font weight",
|
||||
Value::Int(number) => {
|
||||
let [min, max] = [Self::THIN, Self::BLACK];
|
||||
let message = || format!(
|
||||
"should be between {} and {}",
|
||||
min.to_number(),
|
||||
max.to_number(),
|
||||
);
|
||||
|
||||
return if number < i64::from(min.to_number()) {
|
||||
CastResult::Warn(min, message())
|
||||
} else if number > i64::from(max.to_number()) {
|
||||
CastResult::Warn(max, message())
|
||||
} else {
|
||||
CastResult::Ok(Self::from_number(number as u16))
|
||||
};
|
||||
},
|
||||
u16::try_from(number).map_or(Self::BLACK, Self::from_number)
|
||||
}
|
||||
}
|
||||
|
||||
castable! {
|
||||
FontStretch: "font stretch",
|
||||
Value::Relative(relative) => {
|
||||
let [min, max] = [Self::ULTRA_CONDENSED, Self::ULTRA_EXPANDED];
|
||||
let message = || format!(
|
||||
"should be between {} and {}",
|
||||
Relative::new(min.to_ratio() as f64),
|
||||
Relative::new(max.to_ratio() as f64),
|
||||
);
|
||||
|
||||
let ratio = relative.get() as f32;
|
||||
let value = Self::from_ratio(ratio);
|
||||
|
||||
return if ratio < min.to_ratio() || ratio > max.to_ratio() {
|
||||
CastResult::Warn(value, message())
|
||||
} else {
|
||||
CastResult::Ok(value)
|
||||
};
|
||||
},
|
||||
Value::Relative(relative) => Self::from_ratio(relative.get() as f32),
|
||||
}
|
||||
|
||||
castable! {
|
||||
@ -185,7 +158,7 @@ pub fn par(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
|
||||
/// `lang`: Configure the language.
|
||||
pub fn lang(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let iso = args.eat::<EcoString>(ctx).map(|s| lang_dir(&s));
|
||||
let iso = args.eat::<EcoString>().map(|s| lang_dir(&s));
|
||||
let dir = match args.named::<Spanned<Dir>>(ctx, "dir") {
|
||||
Some(dir) if dir.v.axis() == SpecAxis::Horizontal => Some(dir.v),
|
||||
Some(dir) => {
|
||||
@ -235,8 +208,8 @@ fn line_impl(
|
||||
args: &mut FuncArgs,
|
||||
substate: fn(&mut FontState) -> &mut Option<Rc<LineState>>,
|
||||
) -> Value {
|
||||
let stroke = args.eat(ctx).or_else(|| args.named(ctx, "stroke"));
|
||||
let thickness = args.eat(ctx).or_else(|| args.named::<Linear>(ctx, "thickness"));
|
||||
let stroke = args.eat().or_else(|| args.named(ctx, "stroke"));
|
||||
let thickness = args.eat().or_else(|| args.named::<Linear>(ctx, "thickness"));
|
||||
let offset = args.named(ctx, "offset");
|
||||
let extent = args.named(ctx, "extent").unwrap_or_default();
|
||||
let body = args.expect::<Template>(ctx, "body").unwrap_or_default();
|
||||
|
@ -39,7 +39,7 @@ pub fn len(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
/// `rgb`: Create an RGB(A) color.
|
||||
pub fn rgb(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
Value::Color(Color::Rgba(
|
||||
if let Some(string) = args.eat::<Spanned<EcoString>>(ctx) {
|
||||
if let Some(string) = args.eat::<Spanned<EcoString>>() {
|
||||
match RgbaColor::from_str(&string.v) {
|
||||
Ok(color) => color,
|
||||
Err(_) => {
|
||||
@ -48,20 +48,12 @@ pub fn rgb(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let r = args.expect(ctx, "red component");
|
||||
let g = args.expect(ctx, "green component");
|
||||
let b = args.expect(ctx, "blue component");
|
||||
let a = args.eat(ctx);
|
||||
let mut clamp = |component: Option<Spanned<f64>>, default| {
|
||||
component.map_or(default, |c| {
|
||||
if c.v < 0.0 || c.v > 1.0 {
|
||||
ctx.diag(warning!(c.span, "should be between 0.0 and 1.0"));
|
||||
}
|
||||
(c.v.max(0.0).min(1.0) * 255.0).round() as u8
|
||||
})
|
||||
};
|
||||
|
||||
RgbaColor::new(clamp(r, 0), clamp(g, 0), clamp(b, 0), clamp(a, 255))
|
||||
let r = args.expect(ctx, "red component").unwrap_or(0.0);
|
||||
let g = args.expect(ctx, "green component").unwrap_or(0.0);
|
||||
let b = args.expect(ctx, "blue component").unwrap_or(0.0);
|
||||
let a = args.eat().unwrap_or(1.0);
|
||||
let f = |v: f64| (v.clamp(0.0, 1.0) * 255.0).round() as u8;
|
||||
RgbaColor::new(f(r), f(g), f(b), f(a))
|
||||
},
|
||||
))
|
||||
}
|
||||
@ -78,16 +70,17 @@ pub fn max(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
|
||||
/// Find the minimum or maximum of a sequence of values.
|
||||
fn minmax(ctx: &mut EvalContext, args: &mut FuncArgs, goal: Ordering) -> Value {
|
||||
let span = args.span;
|
||||
let mut extremum = None;
|
||||
|
||||
while let Some(value) = args.eat::<Value>(ctx) {
|
||||
for value in args.all::<Value>() {
|
||||
if let Some(prev) = &extremum {
|
||||
match value.partial_cmp(&prev) {
|
||||
Some(ordering) if ordering == goal => extremum = Some(value),
|
||||
Some(_) => {}
|
||||
None => {
|
||||
ctx.diag(error!(
|
||||
args.span,
|
||||
span,
|
||||
"cannot compare {} with {}",
|
||||
prev.type_name(),
|
||||
value.type_name(),
|
||||
|
@ -193,8 +193,7 @@ fn heading(p: &mut Parser) -> SyntaxNode {
|
||||
}
|
||||
|
||||
if level > 6 {
|
||||
p.diag(warning!(start .. p.prev_end(), "should not exceed depth 6"));
|
||||
level = 6;
|
||||
return SyntaxNode::Text(p.eaten_from(start).into());
|
||||
}
|
||||
|
||||
let body = tree_indented(p);
|
||||
|
@ -322,6 +322,11 @@ impl<'s> Parser<'s> {
|
||||
Span::new(start, self.prev_end())
|
||||
}
|
||||
|
||||
/// Return the source string from `start` to the end of the previous token.
|
||||
pub fn eaten_from(&self, start: usize) -> &'s str {
|
||||
self.tokens.scanner().get(start .. self.prev_end())
|
||||
}
|
||||
|
||||
/// Jump to an index in the string.
|
||||
///
|
||||
/// You need to know the correct column.
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
@ -9,7 +9,6 @@
|
||||
====== Level 6
|
||||
|
||||
// Too many hashtags.
|
||||
// Warning: 1-8 should not exceed depth 6
|
||||
======= Level 7
|
||||
|
||||
---
|
||||
|
@ -64,12 +64,6 @@ Emoji: 🐪, 🌋, 🏞
|
||||
// Error: 43-44 expected string or array of strings, found integer
|
||||
#font(style: bold, weight: "thin", serif: 0)[]
|
||||
|
||||
// Warning: 15-19 should be between 100 and 900
|
||||
#font(weight: 2700)[]
|
||||
|
||||
// Warning: 16-21 should be between 50% and 200%
|
||||
#font(stretch: 1000%)[]
|
||||
|
||||
// Error: 7-27 unexpected argument
|
||||
#font(something: "invalid")[]
|
||||
|
||||
|
@ -8,8 +8,7 @@
|
||||
// Alpha channel.
|
||||
#test(rgb(1.0, 0.0, 0.0, 0.5), rgb("ff000080"))
|
||||
|
||||
// Warning: 11-14 should be between 0.0 and 1.0
|
||||
// Warning: 16-20 should be between 0.0 and 1.0
|
||||
// Clamped.
|
||||
#test(rgb(-30, 15.5, 0.5), rgb("00ff80"))
|
||||
|
||||
// Error: 11-15 missing argument: blue component
|
||||
|
Loading…
x
Reference in New Issue
Block a user