1use core::num;
2
3use crate::{
4 ast::AstToken,
5 SyntaxKind::{self, *},
6 SyntaxToken,
7};
8
9macro_rules! token {
10 (
11 #[from($kind:ident)]
12 $(#[$meta:meta])*
13 struct $name:ident;
14 ) => {
15 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
16 $(#[$meta])*
17 pub struct $name(pub(super) SyntaxToken);
18
19 impl std::fmt::Display for $name {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 std::fmt::Display::fmt(self.syntax(), f)
22 }
23 }
24
25 impl AstToken for $name {
26 fn can_cast(kind: SyntaxKind) -> bool {
27 $kind == kind
28 }
29
30 fn cast(from: SyntaxToken) -> Option<Self> {
31 if from.kind() == $kind {
32 Some(Self(from))
33 } else {
34 None
35 }
36 }
37
38 fn syntax(&self) -> &SyntaxToken {
39 &self.0
40 }
41 }
42 };
43}
44
45token! { #[from(TOKEN_WHITESPACE)] struct Whitespace; }
46
47token! { #[from(TOKEN_COMMENT)] struct Comment; }
48
49impl Comment {
50 pub fn text(&self) -> &str {
51 let text = self.syntax().text();
52 match text.strip_prefix("#") {
54 Some(s) => s,
55 None => text.strip_prefix(r#"/*"#).unwrap().strip_suffix(r#"*/"#).unwrap(),
56 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use crate::ast;
63 use crate::match_ast;
64 use crate::Root;
65
66 use super::*;
67 use rowan::ast::AstNode;
68
69 #[test]
70 fn comment() {
71 let s = "# comment bruh
72/* this is a multiline comment wow
73asdfasdf
74asdfasdf */
751 + 1
76/* last one */
77";
78 let comments: Vec<String> = Root::parse(s)
79 .ok()
80 .unwrap()
81 .syntax()
82 .children_with_tokens()
83 .filter_map(|e| match e {
84 rowan::NodeOrToken::Token(token) => match_ast! { match token {
85 ast::Comment(it) => Some(it.text().to_string()),
86 _ => None,
87 }},
88 rowan::NodeOrToken::Node(_) => None,
89 })
90 .collect();
91 let expected = vec![
92 " comment bruh",
93 " this is a multiline comment wow\nasdfasdf\nasdfasdf ",
94 " last one ",
95 ];
96
97 assert_eq!(comments, expected);
98 }
99}
100
101token! { #[from(TOKEN_FLOAT)] struct Float; }
102
103impl Float {
104 pub fn value(&self) -> Result<f64, num::ParseFloatError> {
105 self.syntax().text().parse()
106 }
107}
108
109token! { #[from(TOKEN_INTEGER)] struct Integer; }
110
111impl Integer {
112 pub fn value(&self) -> Result<i64, num::ParseIntError> {
113 self.syntax().text().parse()
114 }
115}
116
117token! { #[from(TOKEN_PATH)] struct PathContent; }
118
119token! { #[from(TOKEN_STRING_CONTENT)] struct StrContent; }
120
121token! { #[from(TOKEN_URI)] struct Uri; }