Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/lib.rs')
| -rw-r--r-- | crates/syntax/src/lib.rs | 48 |
1 files changed, 35 insertions, 13 deletions
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 3a9ebafe87..b5d816b0ce 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -107,14 +107,22 @@ impl<T> Parse<T> { } impl<T: AstNode> Parse<T> { + /// Converts this parse result into a parse result for an untyped syntax tree. pub fn to_syntax(self) -> Parse<SyntaxNode> { Parse { green: self.green, errors: self.errors, _ty: PhantomData } } + /// Gets the parsed syntax tree as a typed ast node. + /// + /// # Panics + /// + /// Panics if the root node cannot be casted into the typed ast node + /// (e.g. if it's an `ERROR` node). pub fn tree(&self) -> T { T::cast(self.syntax_node()).unwrap() } + /// Converts from `Parse<T>` to [`Result<T, Vec<SyntaxError>>`]. pub fn ok(self) -> Result<T, Vec<SyntaxError>> { match self.errors() { errors if !errors.is_empty() => Err(errors), @@ -167,21 +175,40 @@ impl Parse<SourceFile> { } } +impl ast::Expr { + /// Parses an `ast::Expr` from `text`. + /// + /// Note that if the parsed root node is not a valid expression, [`Parse::tree`] will panic. + /// For example: + /// ```rust,should_panic + /// # use syntax::{ast, Edition}; + /// ast::Expr::parse("let fail = true;", Edition::CURRENT).tree(); + /// ``` + pub fn parse(text: &str, edition: Edition) -> Parse<ast::Expr> { + let _p = tracing::info_span!("Expr::parse").entered(); + let (green, errors) = parsing::parse_text_at(text, parser::TopEntryPoint::Expr, edition); + let root = SyntaxNode::new_root(green.clone()); + + assert!( + ast::Expr::can_cast(root.kind()) || root.kind() == SyntaxKind::ERROR, + "{:?} isn't an expression", + root.kind() + ); + Parse::new(green, errors) + } +} + /// `SourceFile` represents a parse tree for a single Rust file. pub use crate::ast::SourceFile; impl SourceFile { pub fn parse(text: &str, edition: Edition) -> Parse<SourceFile> { - let _p = tracing::span!(tracing::Level::INFO, "SourceFile::parse").entered(); + let _p = tracing::info_span!("SourceFile::parse").entered(); let (green, errors) = parsing::parse_text(text, edition); let root = SyntaxNode::new_root(green.clone()); assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE); - Parse { - green, - errors: if errors.is_empty() { None } else { Some(errors.into()) }, - _ty: PhantomData, - } + Parse::new(green, errors) } } @@ -290,12 +317,7 @@ impl ast::TokenTree { } let (green, errors) = builder.finish_raw(); - - Parse { - green, - errors: if errors.is_empty() { None } else { Some(errors.into()) }, - _ty: PhantomData, - } + Parse::new(green, errors) } } @@ -420,7 +442,7 @@ fn api_walkthrough() { assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}'])); assert_eq!( expr_syntax.descendants_with_tokens().count(), - 8, // 5 tokens `1`, ` `, `+`, ` `, `!` + 8, // 5 tokens `1`, ` `, `+`, ` `, `1` // 2 child literal expressions: `1`, `1` // 1 the node itself: `1 + 1` ); |