diff options
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/ast.rs | 26 | ||||
| -rw-r--r-- | src/syntax/highlight.rs | 29 | ||||
| -rw-r--r-- | src/syntax/mod.rs | 101 | ||||
| -rw-r--r-- | src/syntax/pretty.rs | 12 |
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}"); |
