Wrap float literals in their own node
This commit is contained in:
parent
2d5d16f18c
commit
502c519e7d
@ -972,7 +972,7 @@ impl From<ast::LiteralKind> for Literal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LiteralKind::FloatNumber(lit) => {
|
LiteralKind::FloatNumber(lit) => {
|
||||||
let ty = lit.suffix().and_then(BuiltinFloat::from_suffix);
|
let ty = lit.suffix().and_then(|s| BuiltinFloat::from_suffix(&s));
|
||||||
Literal::Float(Default::default(), ty)
|
Literal::Float(Default::default(), ty)
|
||||||
}
|
}
|
||||||
LiteralKind::ByteString(bs) => {
|
LiteralKind::ByteString(bs) => {
|
||||||
|
@ -4,10 +4,7 @@ use base_db::{AnchoredPath, Edition, FileId};
|
|||||||
use cfg::CfgExpr;
|
use cfg::CfgExpr;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
|
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
|
||||||
use syntax::{
|
use syntax::{ast, SmolStr};
|
||||||
ast::{self, AstToken},
|
|
||||||
SmolStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId, MacroCallLoc};
|
use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId, MacroCallLoc};
|
||||||
|
|
||||||
@ -358,14 +355,7 @@ fn unreachable_expand(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn unquote_str(lit: &tt::Literal) -> Option<String> {
|
fn unquote_str(lit: &tt::Literal) -> Option<String> {
|
||||||
let lit = ast::make::tokens::literal(&lit.to_string());
|
let token = ast::make::literal(&lit.to_string()).as_string()?;
|
||||||
let token = ast::String::cast(lit)?;
|
|
||||||
token.value().map(|it| it.into_owned())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unquote_byte_string(lit: &tt::Literal) -> Option<Vec<u8>> {
|
|
||||||
let lit = ast::make::tokens::literal(&lit.to_string());
|
|
||||||
let token = ast::ByteString::cast(lit)?;
|
|
||||||
token.value().map(|it| it.into_owned())
|
token.value().map(|it| it.into_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,12 +432,16 @@ fn concat_bytes_expand(
|
|||||||
for (i, t) in tt.token_trees.iter().enumerate() {
|
for (i, t) in tt.token_trees.iter().enumerate() {
|
||||||
match t {
|
match t {
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
|
tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
|
||||||
let token = ast::make::tokens::literal(&lit.to_string());
|
let lit = ast::make::literal(&lit.to_string());
|
||||||
match token.kind() {
|
match lit.kind() {
|
||||||
syntax::SyntaxKind::BYTE => bytes.push(token.text().to_string()),
|
ast::LiteralKind::ByteString(s) => {
|
||||||
syntax::SyntaxKind::BYTE_STRING => {
|
s.value()
|
||||||
let components = unquote_byte_string(lit).unwrap_or_else(Vec::new);
|
.unwrap_or_default()
|
||||||
components.into_iter().for_each(|x| bytes.push(x.to_string()));
|
.into_iter()
|
||||||
|
.for_each(|x| bytes.push(x.to_string()));
|
||||||
|
}
|
||||||
|
ast::LiteralKind::Byte => {
|
||||||
|
bytes.push(lit.to_string());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
err.get_or_insert(mbe::ExpandError::UnexpectedToken.into());
|
err.get_or_insert(mbe::ExpandError::UnexpectedToken.into());
|
||||||
@ -481,10 +475,10 @@ fn concat_bytes_expand_subtree(
|
|||||||
for (ti, tt) in tree.token_trees.iter().enumerate() {
|
for (ti, tt) in tree.token_trees.iter().enumerate() {
|
||||||
match tt {
|
match tt {
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
|
tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
|
||||||
let lit = ast::make::tokens::literal(&lit.to_string());
|
let lit = ast::make::literal(&lit.to_string());
|
||||||
match lit.kind() {
|
match lit.kind() {
|
||||||
syntax::SyntaxKind::BYTE | syntax::SyntaxKind::INT_NUMBER => {
|
ast::LiteralKind::IntNumber(_) | ast::LiteralKind::Byte => {
|
||||||
bytes.push(lit.text().to_string())
|
bytes.push(lit.to_string());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(mbe::ExpandError::UnexpectedToken.into());
|
return Err(mbe::ExpandError::UnexpectedToken.into());
|
||||||
|
@ -29,7 +29,13 @@ pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
|
if p.at(FLOAT_NUMBER) {
|
||||||
|
let f = p.start();
|
||||||
|
p.bump(FLOAT_NUMBER);
|
||||||
|
f.complete(p, FLOAT_LITERAL);
|
||||||
|
} else {
|
||||||
p.bump_any();
|
p.bump_any();
|
||||||
|
}
|
||||||
Some(m.complete(p, LITERAL))
|
Some(m.complete(p, LITERAL))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -57,6 +57,7 @@ SOURCE_FILE
|
|||||||
EQ "="
|
EQ "="
|
||||||
WHITESPACE " "
|
WHITESPACE " "
|
||||||
LITERAL
|
LITERAL
|
||||||
|
FLOAT_LITERAL
|
||||||
FLOAT_NUMBER "2.0"
|
FLOAT_NUMBER "2.0"
|
||||||
SEMICOLON ";"
|
SEMICOLON ";"
|
||||||
WHITESPACE "\n "
|
WHITESPACE "\n "
|
||||||
|
@ -19,6 +19,7 @@ SOURCE_FILE
|
|||||||
CAST_EXPR
|
CAST_EXPR
|
||||||
METHOD_CALL_EXPR
|
METHOD_CALL_EXPR
|
||||||
LITERAL
|
LITERAL
|
||||||
|
FLOAT_LITERAL
|
||||||
FLOAT_NUMBER "1.0f32"
|
FLOAT_NUMBER "1.0f32"
|
||||||
DOT "."
|
DOT "."
|
||||||
NAME_REF
|
NAME_REF
|
||||||
@ -40,6 +41,7 @@ SOURCE_FILE
|
|||||||
CAST_EXPR
|
CAST_EXPR
|
||||||
METHOD_CALL_EXPR
|
METHOD_CALL_EXPR
|
||||||
LITERAL
|
LITERAL
|
||||||
|
FLOAT_LITERAL
|
||||||
FLOAT_NUMBER "1.0f32"
|
FLOAT_NUMBER "1.0f32"
|
||||||
DOT "."
|
DOT "."
|
||||||
NAME_REF
|
NAME_REF
|
||||||
|
@ -365,13 +365,16 @@ MacroExpr =
|
|||||||
|
|
||||||
Literal =
|
Literal =
|
||||||
Attr* value:(
|
Attr* value:(
|
||||||
'int_number' | 'float_number'
|
'int_number' | FloatLiteral
|
||||||
| 'string' | 'raw_string'
|
| 'string' | 'raw_string'
|
||||||
| 'byte_string' | 'raw_byte_string'
|
| 'byte_string' | 'raw_byte_string'
|
||||||
| 'true' | 'false'
|
| 'true' | 'false'
|
||||||
| 'char' | 'byte'
|
| 'char' | 'byte'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
FloatLiteral =
|
||||||
|
'float_number'
|
||||||
|
|
||||||
PathExpr =
|
PathExpr =
|
||||||
Attr* Path
|
Attr* Path
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ pub enum LiteralKind {
|
|||||||
String(ast::String),
|
String(ast::String),
|
||||||
ByteString(ast::ByteString),
|
ByteString(ast::ByteString),
|
||||||
IntNumber(ast::IntNumber),
|
IntNumber(ast::IntNumber),
|
||||||
FloatNumber(ast::FloatNumber),
|
FloatNumber(ast::FloatLiteral),
|
||||||
Char(ast::Char),
|
Char(ast::Char),
|
||||||
Byte(ast::Byte),
|
Byte(ast::Byte),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
@ -297,16 +297,17 @@ impl ast::Literal {
|
|||||||
}
|
}
|
||||||
pub fn kind(&self) -> LiteralKind {
|
pub fn kind(&self) -> LiteralKind {
|
||||||
let token = match self.value() {
|
let token = match self.value() {
|
||||||
rowan::NodeOrToken::Node(_node) => unreachable!(),
|
rowan::NodeOrToken::Node(node) => {
|
||||||
|
return LiteralKind::FloatNumber(
|
||||||
|
ast::FloatLiteral::cast(node).expect("unreachable"),
|
||||||
|
);
|
||||||
|
}
|
||||||
rowan::NodeOrToken::Token(token) => token,
|
rowan::NodeOrToken::Token(token) => token,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(t) = ast::IntNumber::cast(token.clone()) {
|
if let Some(t) = ast::IntNumber::cast(token.clone()) {
|
||||||
return LiteralKind::IntNumber(t);
|
return LiteralKind::IntNumber(t);
|
||||||
}
|
}
|
||||||
if let Some(t) = ast::FloatNumber::cast(token.clone()) {
|
|
||||||
return LiteralKind::FloatNumber(t);
|
|
||||||
}
|
|
||||||
if let Some(t) = ast::String::cast(token.clone()) {
|
if let Some(t) = ast::String::cast(token.clone()) {
|
||||||
return LiteralKind::String(t);
|
return LiteralKind::String(t);
|
||||||
}
|
}
|
||||||
@ -326,6 +327,26 @@ impl ast::Literal {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_string(&self) -> Option<ast::String> {
|
||||||
|
match self.kind() {
|
||||||
|
LiteralKind::String(it) => Some(it),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_byte_string(&self) -> Option<ast::ByteString> {
|
||||||
|
match self.kind() {
|
||||||
|
LiteralKind::ByteString(it) => Some(it),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ast::FloatLiteral {
|
||||||
|
pub fn suffix(&self) -> Option<String> {
|
||||||
|
ast::FloatNumber::cast(self.syntax().last_token()?)?.suffix().map(|s| s.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BlockModifier {
|
pub enum BlockModifier {
|
||||||
|
@ -1085,6 +1085,16 @@ impl UnderscoreExpr {
|
|||||||
pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
|
pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct FloatLiteral {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl FloatLiteral {
|
||||||
|
pub fn float_number_token(&self) -> Option<SyntaxToken> {
|
||||||
|
support::token(&self.syntax, T![float_number])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct StmtList {
|
pub struct StmtList {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
@ -2719,6 +2729,17 @@ impl AstNode for UnderscoreExpr {
|
|||||||
}
|
}
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
|
impl AstNode for FloatLiteral {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == FLOAT_LITERAL }
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
impl AstNode for StmtList {
|
impl AstNode for StmtList {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
@ -4608,6 +4629,11 @@ impl std::fmt::Display for UnderscoreExpr {
|
|||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for FloatLiteral {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for StmtList {
|
impl std::fmt::Display for StmtList {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
@ -799,6 +799,11 @@ pub fn struct_(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn literal(text: &str) -> ast::Literal {
|
||||||
|
assert_eq!(text.trim(), text);
|
||||||
|
ast_from_text(&format!("fn f() {{ let _ = {}; }}", text))
|
||||||
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn ast_from_text<N: AstNode>(text: &str) -> N {
|
fn ast_from_text<N: AstNode>(text: &str) -> N {
|
||||||
let parse = SourceFile::parse(text);
|
let parse = SourceFile::parse(text);
|
||||||
@ -827,7 +832,7 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken {
|
|||||||
pub mod tokens {
|
pub mod tokens {
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{ast, AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken};
|
use crate::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken};
|
||||||
|
|
||||||
pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| {
|
pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| {
|
||||||
SourceFile::parse(
|
SourceFile::parse(
|
||||||
@ -858,12 +863,6 @@ pub mod tokens {
|
|||||||
sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
|
sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn literal(text: &str) -> SyntaxToken {
|
|
||||||
assert_eq!(text.trim(), text);
|
|
||||||
let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text));
|
|
||||||
lit.syntax().first_child_or_token().unwrap().into_token().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn single_newline() -> SyntaxToken {
|
pub fn single_newline() -> SyntaxToken {
|
||||||
let res = SOURCE_FILE
|
let res = SOURCE_FILE
|
||||||
.tree()
|
.tree()
|
||||||
|
@ -355,14 +355,24 @@ impl Radix {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::ast::{self, make, FloatNumber, IntNumber};
|
use crate::ast::{self, make};
|
||||||
|
|
||||||
fn check_float_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
|
fn check_float_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
|
||||||
assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into());
|
let suffix = match make::literal(lit).kind() {
|
||||||
|
ast::LiteralKind::FloatNumber(f) => f.suffix(),
|
||||||
|
// `1f32` lexes as an INT_NUMBER
|
||||||
|
ast::LiteralKind::IntNumber(i) => i.suffix().map(|s| s.to_string()),
|
||||||
|
e => unreachable!("{e:?}"),
|
||||||
|
};
|
||||||
|
assert_eq!(suffix.as_deref(), expected.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_int_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
|
fn check_int_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
|
||||||
assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into());
|
let i = match make::literal(lit).kind() {
|
||||||
|
ast::LiteralKind::IntNumber(i) => i,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
assert_eq!(i.suffix(), expected.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -390,12 +400,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_string_value<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
|
fn check_string_value<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
|
||||||
assert_eq!(
|
let s = match make::literal(&format!("\"{}\"", lit)).kind() {
|
||||||
ast::String { syntax: make::tokens::literal(&format!("\"{}\"", lit)) }
|
ast::LiteralKind::String(s) => s,
|
||||||
.value()
|
_ => unreachable!(),
|
||||||
.as_deref(),
|
};
|
||||||
expected.into()
|
assert_eq!(s.value().as_deref(), expected.into());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -183,6 +183,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
|||||||
"PATH",
|
"PATH",
|
||||||
"PATH_SEGMENT",
|
"PATH_SEGMENT",
|
||||||
"LITERAL",
|
"LITERAL",
|
||||||
|
"FLOAT_LITERAL",
|
||||||
"RENAME",
|
"RENAME",
|
||||||
"VISIBILITY",
|
"VISIBILITY",
|
||||||
"WHERE_CLAUSE",
|
"WHERE_CLAUSE",
|
||||||
|
@ -462,6 +462,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String {
|
|||||||
[lifetime_ident] => { $crate::SyntaxKind::LIFETIME_IDENT };
|
[lifetime_ident] => { $crate::SyntaxKind::LIFETIME_IDENT };
|
||||||
[ident] => { $crate::SyntaxKind::IDENT };
|
[ident] => { $crate::SyntaxKind::IDENT };
|
||||||
[shebang] => { $crate::SyntaxKind::SHEBANG };
|
[shebang] => { $crate::SyntaxKind::SHEBANG };
|
||||||
|
[float_number] => { $crate::SyntaxKind::FLOAT_NUMBER };
|
||||||
}
|
}
|
||||||
pub use T;
|
pub use T;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user