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
#[macro_use]
mod macros;
mod kinds;
pub mod parser;
pub mod tokenizer;
pub mod types;
pub mod value;
pub use self::{
kinds::SyntaxKind,
parser::AST,
value::{StrPart, Value as NixValue},
};
pub use rowan::{
NodeOrToken, SmolStr, SyntaxElementChildren, SyntaxNodeChildren, TextRange, TextUnit,
TokenAtOffset, WalkEvent,
};
use self::tokenizer::Tokenizer;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum NixLanguage {}
impl rowan::Language for NixLanguage {
type Kind = SyntaxKind;
fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
let discriminant: u16 = raw.0;
assert!(discriminant <= (SyntaxKind::__LAST as u16));
unsafe { std::mem::transmute::<u16, SyntaxKind>(discriminant) }
}
fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
rowan::SyntaxKind(kind as u16)
}
}
pub type SyntaxNode = rowan::SyntaxNode<NixLanguage>;
pub type SyntaxToken = rowan::SyntaxToken<NixLanguage>;
pub type SyntaxElement = rowan::NodeOrToken<SyntaxNode, SyntaxToken>;
pub fn parse(input: &str) -> AST {
parser::parse(Tokenizer::new(input))
}
#[cfg(test)]
mod tests {
use super::{parse, types::*, value::StrPart, NixValue, SyntaxKind};
#[test]
fn interpolation() {
let ast = parse(include_str!("../test_data/general/interpolation.nix"));
let let_in = ast.root().inner().and_then(LetIn::cast).unwrap();
let set = let_in.body().and_then(AttrSet::cast).unwrap();
let entry = set.entries().nth(1).unwrap();
let value = entry.value().and_then(Str::cast).unwrap();
match &*value.parts() {
&[
StrPart::Literal(ref s1),
StrPart::Ast(_),
StrPart::Literal(ref s2),
StrPart::Ast(_),
StrPart::Literal(ref s3)
]
if s1 == "The set\'s x value is: "
&& s2 == "\n\nThis line shall have no indention\n This line shall be indented by 2\n\n\n"
&& s3 == "\n" => (),
parts => panic!("did not match: {:#?}", parts)
}
}
#[test]
fn inherit() {
let ast = parse(include_str!("../test_data/general/inherit.nix"));
let let_in = ast.root().inner().and_then(LetIn::cast).unwrap();
let set = let_in.body().and_then(AttrSet::cast).unwrap();
let inherit = set.inherits().nth(1).unwrap();
let from = inherit.from().unwrap().inner().and_then(Ident::cast).unwrap();
assert_eq!(from.as_str(), "set");
let mut children = inherit.idents();
assert_eq!(children.next().unwrap().as_str(), "z");
assert_eq!(children.next().unwrap().as_str(), "a");
assert!(children.next().is_none());
}
#[test]
fn math() {
let ast = parse(include_str!("../test_data/general/math.nix"));
let root = ast.root().inner().and_then(BinOp::cast).unwrap();
let operation = root.lhs().and_then(BinOp::cast).unwrap();
assert_eq!(root.operator(), BinOpKind::Add);
assert_eq!(operation.operator(), BinOpKind::Add);
let lhs = operation.lhs().and_then(Value::cast).unwrap();
assert_eq!(lhs.to_value(), Ok(NixValue::Integer(1)));
let rhs = operation.rhs().and_then(BinOp::cast).unwrap();
assert_eq!(rhs.operator(), BinOpKind::Mul);
}
#[test]
fn t_macro() {
assert_eq!(T![@], SyntaxKind::TOKEN_AT);
assert!(match SyntaxKind::TOKEN_PAREN_OPEN {
T!["("] => true,
_ => false,
});
}
}