1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
// Copyright contributors to the openqasm-parser project
// SPDX-License-Identifier: Apache-2.0
//! Various extension methods to ast Nodes, which are hard to code-generate.
//! Extensions for various expressions live in a sibling `expr_extensions` module.
//!
//! These methods should only do simple, shallow tasks related to the syntax of the node itself.
use rowan::{GreenNodeData, GreenTokenData};
use std::borrow::Cow;
use crate::{
ast::{self, support, AstNode, SyntaxNode},
NodeOrToken, TokenText,
};
// This function, `text` is borrowed from r-a (may still be commented out below.)
// There is another method, also called `text` implemented for `SyntaxNode`.
// The present function differs in that it returns the text of the first token
// rather than the text of all tokens in the subtree.
//
// This trait needs a better name.
// Several AstNodes have a single token that is a name.
// This includes, but is not limited to, `Name`.
pub trait HasTextName: AstNode {
fn text(&self) -> TokenText<'_> {
text_of_first_token(self.syntax())
}
// FIXME: is this ok? The name of the function does not seem idiomatic
// Nor is returning an owned string. but in practice, at the moment, we always,
// convert text immediately to a `String`.
fn string(&self) -> String {
self.text().to_string()
}
}
impl HasTextName for ast::Param {}
impl HasTextName for ast::Name {}
impl HasTextName for ast::HardwareQubit {}
impl HasTextName for ast::Identifier {}
// This was in the r-a code
// // You didn't really want the name-name, did you?
// impl ast::Name {
// pub fn text(&self) -> TokenText<'_> {
// text_of_first_token(self.syntax())
// }
// }
fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
green_ref
.children()
.next()
.and_then(NodeOrToken::into_token)
.unwrap()
}
match node.green() {
Cow::Borrowed(green_ref) => TokenText::borrowed(first_token(green_ref).text()),
Cow::Owned(green) => TokenText::owned(first_token(&green).to_owned()),
}
}
// TODO: Implementing something like this would be useful.
// Determining which kind of for iterable we have is done in semantic
// analysis by querying via methods on ast::ForIterable
// We could construct an enum here and expose it to consumers.
// #[derive(Clone, Debug, PartialEq, Eq, Hash)]
// pub enum ForIterable {
// SetExpression(ast::SetExpression),
// RangeExpression(ast::RangeExpr),
// Expr(ast::Expr),
// }
// This was carried over from rust. It seems we do not need this any
// longer for disambiguation.
// impl ast::ForStmt {
// // pub fn iterable(&self) -> Option<ForIterable> {
// pub fn iterable(&self) -> Option<ast::Expr> {
// // If the iterable is a BlockExpr, check if the body is missing.
// // If it is, assume the iterable is the expression that is missing instead.
// // let token = self.token();
// // if let Some(t) = ast::SetExpression::cast(token.clone()) {
// // return ForIterable::SetExpression(t);
// // }
// // if let Some(t) = ast::RangeExpr::cast(token.clone()) {
// // return ForIterable::RangeExpression(t);
// // }
// // None
// let mut exprs = support::children(self.syntax());
// let first = exprs.next();
// match first {
// Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
// first => first,
// }
// }
// }
impl ast::AssignmentStmt {
pub fn identifier(&self) -> Option<ast::Identifier> {
support::child(&self.syntax)
}
}
impl ast::HasLoopBody for ast::ForStmt {
fn loop_body(&self) -> Option<ast::BlockExpr> {
let mut exprs = support::children(self.syntax());
let first = exprs.next();
let second = exprs.next();
second.or(first)
}
}
impl ast::WhileStmt {
pub fn condition(&self) -> Option<ast::Expr> {
// If the condition is a BlockExpr, check if the body is missing.
// If it is assume the condition is the expression that is missing instead.
let mut exprs = support::children(self.syntax());
let first = exprs.next();
match first {
Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
first => first,
}
}
// FIXME: need to support both single statement and block.
// Or, can we / should we collapse the distinction already at this level?
pub fn body(&self) -> Option<ast::BlockExpr> {
let mut exprs = support::children(self.syntax());
exprs.next()
}
}
// FIXME: This is wrong. Use `body` above for now. But must sort this out.
impl ast::HasLoopBody for ast::WhileStmt {
fn loop_body(&self) -> Option<ast::BlockExpr> {
let mut exprs = support::children(self.syntax());
let first = exprs.next();
let second = exprs.next();
second.or(first)
}
}
impl ast::PragmaStatement {
fn text(&self) -> TokenText<'_> {
text_of_first_token(self.syntax())
}
// return the pragma line omitting the word "pragma"
pub fn pragma_text(&self) -> String {
let text = self.text();
if text.starts_with('#') {
text[7..].to_string()
} else {
text[6..].to_string()
}
}
}
impl ast::AnnotationStatement {
fn text(&self) -> TokenText<'_> {
text_of_first_token(self.syntax())
}
pub fn annotation_text(&self) -> String {
self.text().to_string()
}
}