Wrap float literals in their own node

This commit is contained in:
Jonas Schievink 2022-05-03 19:56:10 +02:00
parent 2d5d16f18c
commit 502c519e7d
13 changed files with 113 additions and 49 deletions

View File

@ -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) => {

View File

@ -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());

View File

@ -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

View File

@ -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 "

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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)

View File

@ -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()

View File

@ -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]

View File

@ -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",

View File

@ -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;
}; };