summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/ast.rs26
-rw-r--r--src/syntax/highlight.rs29
-rw-r--r--src/syntax/mod.rs101
-rw-r--r--src/syntax/pretty.rs12
4 files changed, 114 insertions, 54 deletions
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index 8df25f59..ae8ecdc9 100644
--- a/src/syntax/ast.rs
+++ b/src/syntax/ast.rs
@@ -1,4 +1,6 @@
//! A typed layer over the red-green tree.
+//!
+//! The AST is rooted in the [`Markup`] node.
use std::ops::Deref;
@@ -211,6 +213,8 @@ pub enum Expr {
With(WithExpr),
/// A let expression: `let x = 1`.
Let(LetExpr),
+ /// A set expression: `set text(...)`.
+ Set(SetExpr),
/// An if-else expression: `if x { y } else { z }`.
If(IfExpr),
/// A while loop expression: `while x { y }`.
@@ -238,6 +242,7 @@ impl TypedNode for Expr {
NodeKind::Closure => node.cast().map(Self::Closure),
NodeKind::WithExpr => node.cast().map(Self::With),
NodeKind::LetExpr => node.cast().map(Self::Let),
+ NodeKind::SetExpr => node.cast().map(Self::Set),
NodeKind::IfExpr => node.cast().map(Self::If),
NodeKind::WhileExpr => node.cast().map(Self::While),
NodeKind::ForExpr => node.cast().map(Self::For),
@@ -262,6 +267,7 @@ impl TypedNode for Expr {
Self::Closure(v) => v.as_red(),
Self::With(v) => v.as_red(),
Self::Let(v) => v.as_red(),
+ Self::Set(v) => v.as_red(),
Self::If(v) => v.as_red(),
Self::While(v) => v.as_red(),
Self::For(v) => v.as_red(),
@@ -279,6 +285,7 @@ impl Expr {
Self::Ident(_)
| Self::Call(_)
| Self::Let(_)
+ | Self::Set(_)
| Self::If(_)
| Self::While(_)
| Self::For(_)
@@ -838,6 +845,25 @@ impl LetExpr {
}
node! {
+ /// A set expression: `set text(...)`.
+ SetExpr
+}
+
+impl SetExpr {
+ /// The class to set style properties for.
+ pub fn class(&self) -> Ident {
+ self.0.cast_first_child().expect("set expression is missing class")
+ }
+
+ /// The style properties to set.
+ pub fn args(&self) -> CallArgs {
+ self.0
+ .cast_first_child()
+ .expect("set expression is missing argument list")
+ }
+}
+
+node! {
/// An import expression: `import a, b, c from "utils.typ"`.
ImportExpr
}
diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs
index 22e6cf50..85fbef12 100644
--- a/src/syntax/highlight.rs
+++ b/src/syntax/highlight.rs
@@ -96,22 +96,23 @@ impl Category {
NodeKind::EnDash => Some(Category::Shortcut),
NodeKind::EmDash => Some(Category::Shortcut),
NodeKind::Escape(_) => Some(Category::Escape),
+ NodeKind::Not => Some(Category::Keyword),
+ NodeKind::And => Some(Category::Keyword),
+ NodeKind::Or => Some(Category::Keyword),
+ NodeKind::With => Some(Category::Keyword),
NodeKind::Let => Some(Category::Keyword),
+ NodeKind::Set => Some(Category::Keyword),
NodeKind::If => Some(Category::Keyword),
NodeKind::Else => Some(Category::Keyword),
+ NodeKind::While => Some(Category::Keyword),
NodeKind::For => Some(Category::Keyword),
NodeKind::In => Some(Category::Keyword),
- NodeKind::While => Some(Category::Keyword),
NodeKind::Break => Some(Category::Keyword),
NodeKind::Continue => Some(Category::Keyword),
NodeKind::Return => Some(Category::Keyword),
NodeKind::Import => Some(Category::Keyword),
- NodeKind::Include => Some(Category::Keyword),
NodeKind::From => Some(Category::Keyword),
- NodeKind::Not => Some(Category::Keyword),
- NodeKind::And => Some(Category::Keyword),
- NodeKind::Or => Some(Category::Keyword),
- NodeKind::With => Some(Category::Keyword),
+ NodeKind::Include => Some(Category::Keyword),
NodeKind::Plus => Some(Category::Operator),
NodeKind::Star => Some(Category::Operator),
NodeKind::Slash => Some(Category::Operator),
@@ -139,6 +140,7 @@ impl Category {
Some(Category::Function)
}
NodeKind::WithExpr => Some(Category::Function),
+ NodeKind::SetExpr => Some(Category::Function),
NodeKind::Call => Some(Category::Function),
_ => Some(Category::Variable),
},
@@ -161,21 +163,22 @@ impl Category {
NodeKind::Array => None,
NodeKind::Dict => None,
NodeKind::Named => None,
+ NodeKind::Template => None,
NodeKind::Group => None,
+ NodeKind::Block => None,
NodeKind::Unary => None,
NodeKind::Binary => None,
NodeKind::Call => None,
NodeKind::CallArgs => None,
+ NodeKind::Spread => None,
NodeKind::Closure => None,
NodeKind::ClosureParams => None,
- NodeKind::Spread => None,
- NodeKind::Template => None,
- NodeKind::Block => None,
- NodeKind::ForExpr => None,
- NodeKind::WhileExpr => None,
- NodeKind::IfExpr => None,
- NodeKind::LetExpr => None,
NodeKind::WithExpr => None,
+ NodeKind::LetExpr => None,
+ NodeKind::SetExpr => None,
+ NodeKind::IfExpr => None,
+ NodeKind::WhileExpr => None,
+ NodeKind::ForExpr => None,
NodeKind::ForPattern => None,
NodeKind::ImportExpr => None,
NodeKind::ImportItems => None,
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index e9011a4d..d9ad42a8 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -83,19 +83,15 @@ impl Default for Green {
impl Debug for Green {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "{:?}: {}", self.kind(), self.len())?;
- if let Self::Node(n) = self {
- if !n.children.is_empty() {
- f.write_str(" ")?;
- f.debug_list().entries(&n.children).finish()?;
- }
+ match self {
+ Self::Node(node) => node.fmt(f),
+ Self::Token(token) => token.fmt(f),
}
- Ok(())
}
}
/// An inner node in the untyped green tree.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Clone, PartialEq)]
pub struct GreenNode {
/// Node metadata.
data: GreenData,
@@ -145,8 +141,19 @@ impl From<Rc<GreenNode>> for Green {
}
}
+impl Debug for GreenNode {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ self.data.fmt(f)?;
+ if !self.children.is_empty() {
+ f.write_str(" ")?;
+ f.debug_list().entries(&self.children).finish()?;
+ }
+ Ok(())
+ }
+}
+
/// Data shared between inner and leaf nodes.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Clone, PartialEq)]
pub struct GreenData {
/// What kind of node this is (each kind would have its own struct in a
/// strongly typed AST).
@@ -178,6 +185,12 @@ impl From<GreenData> for Green {
}
}
+impl Debug for GreenData {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ write!(f, "{:?}: {}", self.kind, self.len)
+ }
+}
+
/// A owned wrapper for a green node with span information.
///
/// Owned variant of [`RedRef`]. Can be [cast](Self::cast) to an AST node.
@@ -465,6 +478,8 @@ pub enum NodeKind {
Auto,
/// The `let` keyword.
Let,
+ /// The `set` keyword.
+ Set,
/// The `if` keyword.
If,
/// The `else` keyword.
@@ -552,8 +567,12 @@ pub enum NodeKind {
Dict,
/// A named pair: `thickness: 3pt`.
Named,
+ /// A template expression: `[*Hi* there!]`.
+ Template,
/// A grouped expression: `(1 + 2)`.
Group,
+ /// A block expression: `{ let x = 1; x + 2 }`.
+ Block,
/// A unary operation: `-x`.
Unary,
/// A binary operation: `a + b`.
@@ -562,39 +581,37 @@ pub enum NodeKind {
Call,
/// A function call's argument list: `(x, y)`.
CallArgs,
+ /// Spreaded arguments or a parameter sink: `..x`.
+ Spread,
/// A closure expression: `(x, y) => z`.
Closure,
/// A closure's parameters: `(x, y)`.
ClosureParams,
- /// A parameter sink: `..x`.
- Spread,
- /// A template expression: `[*Hi* there!]`.
- Template,
- /// A block expression: `{ let x = 1; x + 2 }`.
- Block,
- /// A for loop expression: `for x in y { ... }`.
- ForExpr,
- /// A while loop expression: `while x { ... }`.
- WhileExpr,
- /// An if expression: `if x { ... }`.
- IfExpr,
+ /// A with expression: `f with (x, y: 1)`.
+ WithExpr,
/// A let expression: `let x = 1`.
LetExpr,
- /// The `with` expression: `with (1)`.
- WithExpr,
+ /// A set expression: `set text(...)`.
+ SetExpr,
+ /// An if-else expression: `if x { y } else { z }`.
+ IfExpr,
+ /// A while loop expression: `while x { ... }`.
+ WhileExpr,
+ /// A for loop expression: `for x in y { ... }`.
+ ForExpr,
/// A for loop's destructuring pattern: `x` or `x, y`.
ForPattern,
- /// The import expression: `import x from "foo.typ"`.
+ /// An import expression: `import a, b, c from "utils.typ"`.
ImportExpr,
/// Items to import: `a, b, c`.
ImportItems,
- /// The include expression: `include "foo.typ"`.
+ /// An include expression: `include "chapter1.typ"`.
IncludeExpr,
- /// Two slashes followed by inner contents, terminated with a newline:
- /// `//<str>\n`.
+ /// A line comment, two slashes followed by inner contents, terminated with
+ /// a newline: `//<str>\n`.
LineComment,
- /// A slash and a star followed by inner contents, terminated with a star
- /// and a slash: `/*<str>*/`.
+ /// A block comment, a slash and a star followed by inner contents,
+ /// terminated with a star and a slash: `/*<str>*/`.
///
/// The comment can contain nested block comments.
BlockComment,
@@ -616,11 +633,6 @@ pub enum ErrorPos {
}
impl NodeKind {
- /// Whether this is some kind of parenthesis.
- pub fn is_paren(&self) -> bool {
- matches!(self, Self::LeftParen | Self::RightParen)
- }
-
/// Whether this is some kind of bracket.
pub fn is_bracket(&self) -> bool {
matches!(self, Self::LeftBracket | Self::RightBracket)
@@ -631,6 +643,11 @@ impl NodeKind {
matches!(self, Self::LeftBrace | Self::RightBrace)
}
+ /// Whether this is some kind of parenthesis.
+ pub fn is_paren(&self) -> bool {
+ matches!(self, Self::LeftParen | Self::RightParen)
+ }
+
/// Whether this is some kind of error.
pub fn is_error(&self) -> bool {
matches!(self, NodeKind::Error(_, _) | NodeKind::Unknown(_))
@@ -672,6 +689,7 @@ impl NodeKind {
Self::None => "`none`",
Self::Auto => "`auto`",
Self::Let => "keyword `let`",
+ Self::Set => "keyword `set`",
Self::If => "keyword `if`",
Self::Else => "keyword `else`",
Self::For => "keyword `for`",
@@ -712,21 +730,22 @@ impl NodeKind {
Self::Array => "array",
Self::Dict => "dictionary",
Self::Named => "named argument",
+ Self::Template => "template",
Self::Group => "group",
+ Self::Block => "block",
Self::Unary => "unary expression",
Self::Binary => "binary expression",
Self::Call => "call",
Self::CallArgs => "call arguments",
+ Self::Spread => "parameter sink",
Self::Closure => "closure",
Self::ClosureParams => "closure parameters",
- Self::Spread => "parameter sink",
- Self::Template => "template",
- Self::Block => "block",
- Self::ForExpr => "for-loop expression",
- Self::WhileExpr => "while-loop expression",
- Self::IfExpr => "`if` expression",
- Self::LetExpr => "`let` expression",
Self::WithExpr => "`with` expression",
+ Self::LetExpr => "`let` expression",
+ Self::SetExpr => "`set` expression",
+ Self::IfExpr => "`if` expression",
+ Self::WhileExpr => "while-loop expression",
+ Self::ForExpr => "for-loop expression",
Self::ForPattern => "for-loop destructuring pattern",
Self::ImportExpr => "`import` expression",
Self::ImportItems => "import items",
diff --git a/src/syntax/pretty.rs b/src/syntax/pretty.rs
index c453fb56..62ecb8cd 100644
--- a/src/syntax/pretty.rs
+++ b/src/syntax/pretty.rs
@@ -225,6 +225,7 @@ impl Pretty for Expr {
Self::Closure(v) => v.pretty(p),
Self::With(v) => v.pretty(p),
Self::Let(v) => v.pretty(p),
+ Self::Set(v) => v.pretty(p),
Self::If(v) => v.pretty(p),
Self::While(v) => v.pretty(p),
Self::For(v) => v.pretty(p),
@@ -444,6 +445,16 @@ impl Pretty for LetExpr {
}
}
+impl Pretty for SetExpr {
+ fn pretty(&self, p: &mut Printer) {
+ p.push_str("set ");
+ self.class().pretty(p);
+ p.push_str("(");
+ self.args().pretty(p);
+ p.push(')');
+ }
+}
+
impl Pretty for IfExpr {
fn pretty(&self, p: &mut Printer) {
p.push_str("if ");
@@ -639,6 +650,7 @@ mod tests {
// Control flow.
roundtrip("#let x = 1 + 2");
roundtrip("#let f(x) = y");
+ roundtrip("#set text(size: 12pt)");
roundtrip("#if x [y] else [z]");
roundtrip("#if x {} else if y {} else {}");
roundtrip("#while x {y}");