Eliminate literal type

This commit is contained in:
Laurenz 2023-01-14 12:49:26 +01:00
parent ab03f32240
commit 15f0434d1f
2 changed files with 247 additions and 132 deletions

View File

@ -270,8 +270,9 @@ impl Eval for ast::Expr {
Self::SmartQuote(v) => v.eval(vm).map(Value::Content),
Self::Strong(v) => v.eval(vm).map(Value::Content),
Self::Emph(v) => v.eval(vm).map(Value::Content),
Self::Link(v) => v.eval(vm).map(Value::Content),
Self::Raw(v) => v.eval(vm).map(Value::Content),
Self::Link(v) => v.eval(vm).map(Value::Content),
Self::Label(v) => v.eval(vm),
Self::Ref(v) => v.eval(vm).map(Value::Content),
Self::Heading(v) => v.eval(vm).map(Value::Content),
Self::List(v) => v.eval(vm).map(Value::Content),
@ -281,8 +282,14 @@ impl Eval for ast::Expr {
Self::Script(v) => v.eval(vm).map(Value::Content),
Self::Frac(v) => v.eval(vm).map(Value::Content),
Self::AlignPoint(v) => v.eval(vm).map(Value::Content),
Self::Lit(v) => v.eval(vm),
Self::Ident(v) => v.eval(vm),
Self::None(v) => v.eval(vm),
Self::Auto(v) => v.eval(vm),
Self::Bool(v) => v.eval(vm),
Self::Int(v) => v.eval(vm),
Self::Float(v) => v.eval(vm),
Self::Numeric(v) => v.eval(vm),
Self::Str(v) => v.eval(vm),
Self::Code(v) => v.eval(vm),
Self::Content(v) => v.eval(vm).map(Value::Content),
Self::Math(v) => v.eval(vm).map(Value::Content),
@ -435,6 +442,14 @@ impl Eval for ast::Link {
}
}
impl Eval for ast::Label {
type Output = Value;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
Ok(Value::Label(Label(self.get().clone())))
}
}
impl Eval for ast::Ref {
type Output = Content;
@ -531,29 +546,6 @@ impl Eval for ast::AlignPoint {
}
}
impl Eval for ast::Lit {
type Output = Value;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
Ok(match self.kind() {
ast::LitKind::None => Value::None,
ast::LitKind::Auto => Value::Auto,
ast::LitKind::Bool(v) => Value::Bool(v),
ast::LitKind::Int(v) => Value::Int(v),
ast::LitKind::Float(v) => Value::Float(v),
ast::LitKind::Numeric(v, unit) => match unit {
Unit::Length(unit) => Abs::with_unit(v, unit).into(),
Unit::Angle(unit) => Angle::with_unit(v, unit).into(),
Unit::Em => Em::new(v).into(),
Unit::Fr => Fr::new(v).into(),
Unit::Percent => Ratio::new(v / 100.0).into(),
},
ast::LitKind::Str(v) => Value::Str(v.into()),
ast::LitKind::Label(v) => Value::Label(Label(v)),
})
}
}
impl Eval for ast::Ident {
type Output = Value;
@ -578,6 +570,69 @@ impl ast::Ident {
}
}
impl Eval for ast::None {
type Output = Value;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
Ok(Value::None)
}
}
impl Eval for ast::Auto {
type Output = Value;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
Ok(Value::Auto)
}
}
impl Eval for ast::Bool {
type Output = Value;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
Ok(Value::Bool(self.get()))
}
}
impl Eval for ast::Int {
type Output = Value;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
Ok(Value::Int(self.get()))
}
}
impl Eval for ast::Float {
type Output = Value;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
Ok(Value::Float(self.get()))
}
}
impl Eval for ast::Numeric {
type Output = Value;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
let (v, unit) = self.get();
Ok(match unit {
Unit::Length(unit) => Abs::with_unit(v, unit).into(),
Unit::Angle(unit) => Angle::with_unit(v, unit).into(),
Unit::Em => Em::new(v).into(),
Unit::Fr => Fr::new(v).into(),
Unit::Percent => Ratio::new(v / 100.0).into(),
})
}
}
impl Eval for ast::Str {
type Output = Value;
fn eval(&self, _: &mut Vm) -> SourceResult<Self::Output> {
Ok(Value::Str(self.get().clone().into()))
}
}
impl Eval for ast::CodeBlock {
type Output = Value;

View File

@ -37,7 +37,7 @@ macro_rules! node {
if matches!(node.kind(), $variants) {
Some(Self(node.clone()))
} else {
None
Option::None
}
}
@ -97,6 +97,8 @@ pub enum Expr {
Raw(Raw),
/// A hyperlink: `https://typst.org`.
Link(Link),
/// A label: `<intro>`.
Label(Label),
/// A reference: `@target`.
Ref(Ref),
/// A section heading: `= Introduction`.
@ -117,10 +119,22 @@ pub enum Expr {
Frac(Frac),
/// An alignment point in a math formula: `&`, `&&`.
AlignPoint(AlignPoint),
/// A literal: `1`, `true`, ...
Lit(Lit),
/// An identifier: `left`.
Ident(Ident),
/// The `none` literal.
None(None),
/// The `auto` literal.
Auto(Auto),
/// A boolean: `true`, `false`.
Bool(Bool),
/// An integer: `120`.
Int(Int),
/// A floating-point number: `1.2`, `10e-4`.
Float(Float),
/// A numeric value with a unit: `12pt`, `3cm`, `2em`, `90deg`, `50%`.
Numeric(Numeric),
/// A quoted string: `"..."`.
Str(Str),
/// A code block: `{ let x = 1; x + 2 }`.
Code(CodeBlock),
/// A content block: `[*Hi* there!]`.
@ -189,6 +203,7 @@ impl AstNode for Expr {
SyntaxKind::Emph => node.cast().map(Self::Emph),
SyntaxKind::Raw(_) => node.cast().map(Self::Raw),
SyntaxKind::Link(_) => node.cast().map(Self::Link),
SyntaxKind::Label(_) => node.cast().map(Self::Label),
SyntaxKind::Ref(_) => node.cast().map(Self::Ref),
SyntaxKind::Heading => node.cast().map(Self::Heading),
SyntaxKind::ListItem => node.cast().map(Self::List),
@ -200,6 +215,13 @@ impl AstNode for Expr {
SyntaxKind::Frac => node.cast().map(Self::Frac),
SyntaxKind::AlignPoint => node.cast().map(Self::AlignPoint),
SyntaxKind::Ident(_) => node.cast().map(Self::Ident),
SyntaxKind::None => node.cast().map(Self::None),
SyntaxKind::Auto => node.cast().map(Self::Auto),
SyntaxKind::Bool(_) => node.cast().map(Self::Bool),
SyntaxKind::Int(_) => node.cast().map(Self::Int),
SyntaxKind::Float(_) => node.cast().map(Self::Float),
SyntaxKind::Numeric(_, _) => node.cast().map(Self::Numeric),
SyntaxKind::Str(_) => node.cast().map(Self::Str),
SyntaxKind::CodeBlock => node.cast().map(Self::Code),
SyntaxKind::ContentBlock => node.cast().map(Self::Content),
SyntaxKind::Parenthesized => node.cast().map(Self::Parenthesized),
@ -222,7 +244,7 @@ impl AstNode for Expr {
SyntaxKind::LoopBreak => node.cast().map(Self::Break),
SyntaxKind::LoopContinue => node.cast().map(Self::Continue),
SyntaxKind::FuncReturn => node.cast().map(Self::Return),
_ => node.cast().map(Self::Lit),
_ => Option::None,
}
}
@ -239,6 +261,7 @@ impl AstNode for Expr {
Self::Emph(v) => v.as_untyped(),
Self::Raw(v) => v.as_untyped(),
Self::Link(v) => v.as_untyped(),
Self::Label(v) => v.as_untyped(),
Self::Ref(v) => v.as_untyped(),
Self::Heading(v) => v.as_untyped(),
Self::List(v) => v.as_untyped(),
@ -249,10 +272,16 @@ impl AstNode for Expr {
Self::Script(v) => v.as_untyped(),
Self::Frac(v) => v.as_untyped(),
Self::AlignPoint(v) => v.as_untyped(),
Self::Lit(v) => v.as_untyped(),
Self::Ident(v) => v.as_untyped(),
Self::None(v) => v.as_untyped(),
Self::Auto(v) => v.as_untyped(),
Self::Bool(v) => v.as_untyped(),
Self::Int(v) => v.as_untyped(),
Self::Float(v) => v.as_untyped(),
Self::Numeric(v) => v.as_untyped(),
Self::Str(v) => v.as_untyped(),
Self::Code(v) => v.as_untyped(),
Self::Content(v) => v.as_untyped(),
Self::Ident(v) => v.as_untyped(),
Self::Array(v) => v.as_untyped(),
Self::Dict(v) => v.as_untyped(),
Self::Parenthesized(v) => v.as_untyped(),
@ -277,25 +306,6 @@ impl AstNode for Expr {
}
}
impl Expr {
/// Whether the expression can be shortened in markup with a hashtag.
pub fn has_short_form(&self) -> bool {
matches!(
self,
Self::Ident(_)
| Self::FuncCall(_)
| Self::Let(_)
| Self::Set(_)
| Self::Show(_)
| Self::Conditional(_)
| Self::While(_)
| Self::For(_)
| Self::Import(_)
| Self::Include(_)
)
}
}
node! {
/// Whitespace.
Space
@ -463,6 +473,21 @@ impl Link {
}
}
node! {
/// A label: `<intro>`.
Label
}
impl Label {
/// Get the label's text.
pub fn get(&self) -> &EcoString {
match self.0.kind() {
SyntaxKind::Label(v) => v,
_ => panic!("label is of wrong kind"),
}
}
}
node! {
/// A reference: `@target`.
Ref
@ -522,7 +547,7 @@ impl EnumItem {
pub fn number(&self) -> Option<NonZeroUsize> {
self.0.children().find_map(|node| match node.kind() {
SyntaxKind::EnumNumbering(num) => Some(*num),
_ => None,
_ => Option::None,
})
}
@ -649,53 +674,124 @@ impl AlignPoint {
}
node! {
/// A literal: `1`, `true`, ...
Lit: SyntaxKind::None
| SyntaxKind::Auto
| SyntaxKind::Bool(_)
| SyntaxKind::Int(_)
| SyntaxKind::Float(_)
| SyntaxKind::Numeric(_, _)
| SyntaxKind::Str(_)
| SyntaxKind::Label(_)
/// An identifier: `it`.
Ident
}
impl Lit {
/// The kind of literal.
pub fn kind(&self) -> LitKind {
match *self.0.kind() {
SyntaxKind::None => LitKind::None,
SyntaxKind::Auto => LitKind::Auto,
SyntaxKind::Bool(v) => LitKind::Bool(v),
SyntaxKind::Int(v) => LitKind::Int(v),
SyntaxKind::Float(v) => LitKind::Float(v),
SyntaxKind::Numeric(v, unit) => LitKind::Numeric(v, unit),
SyntaxKind::Str(ref v) => LitKind::Str(v.clone()),
SyntaxKind::Label(ref v) => LitKind::Label(v.clone()),
_ => panic!("literal is of wrong kind"),
impl Ident {
/// Get the identifier.
pub fn get(&self) -> &EcoString {
match self.0.kind() {
SyntaxKind::Ident(id) => id,
_ => panic!("identifier is of wrong kind"),
}
}
/// Take out the container identifier.
pub fn take(self) -> EcoString {
match self.0.take() {
SyntaxKind::Ident(id) => id,
_ => panic!("identifier is of wrong kind"),
}
}
/// Get the identifier as a string slice.
pub fn as_str(&self) -> &str {
self.get()
}
}
impl Deref for Ident {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
node! {
/// The `none` literal.
None
}
node! {
/// The `auto` literal.
Auto
}
node! {
/// A boolean: `true`, `false`.
Bool
}
impl Bool {
/// Get the value.
pub fn get(&self) -> bool {
match self.0.kind() {
SyntaxKind::Bool(v) => *v,
_ => panic!("boolean is of wrong kind"),
}
}
}
/// The kind of a literal.
#[derive(Debug, Clone, PartialEq)]
pub enum LitKind {
/// The none literal: `none`.
None,
/// The auto literal: `auto`.
Auto,
/// A boolean: `true`, `false`.
Bool(bool),
node! {
/// An integer: `120`.
Int(i64),
Int
}
impl Int {
/// Get the value.
pub fn get(&self) -> i64 {
match self.0.kind() {
SyntaxKind::Int(v) => *v,
_ => panic!("integer is of wrong kind"),
}
}
}
node! {
/// A floating-point number: `1.2`, `10e-4`.
Float(f64),
Float
}
impl Float {
/// Get the value.
pub fn get(&self) -> f64 {
match self.0.kind() {
SyntaxKind::Float(v) => *v,
_ => panic!("float is of wrong kind"),
}
}
}
node! {
/// A numeric value with a unit: `12pt`, `3cm`, `2em`, `90deg`, `50%`.
Numeric(f64, Unit),
Numeric
}
impl Numeric {
/// Get the value and unit.
pub fn get(&self) -> (f64, Unit) {
match self.0.kind() {
SyntaxKind::Numeric(v, unit) => (*v, *unit),
_ => panic!("numeric is of wrong kind"),
}
}
}
node! {
/// A quoted string: `"..."`.
Str(EcoString),
/// A label: `<intro>`.
Label(EcoString),
Str
}
impl Str {
/// Get the value.
pub fn get(&self) -> &EcoString {
match self.0.kind() {
SyntaxKind::Str(v) => v,
_ => panic!("string is of wrong kind"),
}
}
}
node! {
@ -802,7 +898,7 @@ impl AstNode for DictItem {
SyntaxKind::Named => node.cast().map(Self::Named),
SyntaxKind::Keyed => node.cast().map(Self::Keyed),
SyntaxKind::Spread => node.cast_first_child().map(Self::Spread),
_ => None,
_ => Option::None,
}
}
@ -844,7 +940,7 @@ impl Keyed {
.children()
.find_map(|node| match node.kind() {
SyntaxKind::Str(key) => Some(key.clone()),
_ => None,
_ => Option::None,
})
.expect("keyed pair is missing key")
}
@ -893,7 +989,7 @@ impl UnOp {
SyntaxKind::Plus => Self::Pos,
SyntaxKind::Minus => Self::Neg,
SyntaxKind::Not => Self::Not,
_ => return None,
_ => return Option::None,
})
}
@ -929,7 +1025,7 @@ impl Binary {
.find_map(|node| match node.kind() {
SyntaxKind::Not => {
not = true;
None
Option::None
}
SyntaxKind::In if not => Some(BinOp::NotIn),
_ => BinOp::from_token(node.kind()),
@ -1017,7 +1113,7 @@ impl BinOp {
SyntaxKind::HyphEq => Self::SubAssign,
SyntaxKind::StarEq => Self::MulAssign,
SyntaxKind::SlashEq => Self::DivAssign,
_ => return None,
_ => return Option::None,
})
}
@ -1253,7 +1349,7 @@ impl AstNode for Param {
SyntaxKind::Ident(_) => node.cast().map(Self::Pos),
SyntaxKind::Named => node.cast().map(Self::Named),
SyntaxKind::Spread => node.cast_first_child().map(Self::Sink),
_ => None,
_ => Option::None,
}
}
@ -1419,7 +1515,7 @@ impl ForPattern {
if children.next().is_some() {
key
} else {
None
Option::None
}
}
@ -1448,7 +1544,7 @@ impl ModuleImport {
let items = node.children().filter_map(SyntaxNode::cast).collect();
Some(Imports::Items(items))
}
_ => None,
_ => Option::None,
})
}
}
@ -1495,39 +1591,3 @@ impl FuncReturn {
self.0.cast_last_child()
}
}
node! {
/// An identifier: `it`.
Ident
}
impl Ident {
/// Get the identifier.
pub fn get(&self) -> &EcoString {
match self.0.kind() {
SyntaxKind::Ident(id) => id,
_ => panic!("identifier is of wrong kind"),
}
}
/// Take out the container identifier.
pub fn take(self) -> EcoString {
match self.0.take() {
SyntaxKind::Ident(id) => id,
_ => panic!("identifier is of wrong kind"),
}
}
/// Get the identifier as a string slice.
pub fn as_str(&self) -> &str {
self.get()
}
}
impl Deref for Ident {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}