169 lines
4.6 KiB
Rust
169 lines
4.6 KiB
Rust
use rowan::ast::AstNode;
|
|
|
|
use crate::{FileId, ast};
|
|
|
|
pub fn parse_file(file_id: FileId, source: &str) -> ast::ParsedFile {
|
|
let parse = rnix::Root::parse(source);
|
|
let source_len = source.len();
|
|
|
|
let (nodes, tokens) = convert_syntax(parse.syntax());
|
|
|
|
ast::ParsedFile {
|
|
file_id,
|
|
nodes,
|
|
tokens,
|
|
errors: parse
|
|
.errors()
|
|
.iter()
|
|
.map(|error| convert_parse_error(error, source_len))
|
|
.collect(),
|
|
}
|
|
}
|
|
|
|
fn convert_syntax(syntax: rnix::SyntaxNode) -> (Vec<ast::Node>, Vec<ast::Token>) {
|
|
let mut nodes = Vec::new();
|
|
let mut tokens = Vec::new();
|
|
|
|
for element in syntax.descendants_with_tokens() {
|
|
match element {
|
|
rnix::NodeOrToken::Node(node) => nodes.extend(convert_node(node)),
|
|
rnix::NodeOrToken::Token(token) => tokens.extend(convert_token(token)),
|
|
}
|
|
}
|
|
|
|
(nodes, tokens)
|
|
}
|
|
|
|
fn convert_node(node: rnix::SyntaxNode) -> Option<ast::Node> {
|
|
match node.kind() {
|
|
rnix::SyntaxKind::NODE_APPLY => convert_apply(node),
|
|
rnix::SyntaxKind::NODE_INHERIT => convert_inherit(node),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn convert_apply(node: rnix::SyntaxNode) -> Option<ast::Node> {
|
|
let apply = rnix::ast::Apply::cast(node)?;
|
|
let range = apply.syntax().text_range().into();
|
|
let data = apply.try_into().ok()?;
|
|
|
|
Some(ast::Node {
|
|
range,
|
|
data: ast::NodeData::Apply(data),
|
|
})
|
|
}
|
|
|
|
impl TryFrom<rnix::ast::Apply> for ast::Apply {
|
|
type Error = ();
|
|
|
|
fn try_from(apply: rnix::ast::Apply) -> Result<Self, Self::Error> {
|
|
Ok(Self {
|
|
function: apply.lambda().ok_or(())?.try_into()?,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl TryFrom<rnix::ast::Expr> for ast::Expr {
|
|
type Error = ();
|
|
|
|
fn try_from(expr: rnix::ast::Expr) -> Result<Self, Self::Error> {
|
|
match expr {
|
|
rnix::ast::Expr::Ident(ident) => Ok(Self::Ident(ident.into())),
|
|
rnix::ast::Expr::Select(select) => Ok(Self::Select(Box::new(select.try_into()?))),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<rnix::ast::Ident> for ast::Ident {
|
|
fn from(ident: rnix::ast::Ident) -> Self {
|
|
Self {
|
|
name: ident.to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<rnix::ast::Select> for ast::Select {
|
|
type Error = ();
|
|
|
|
fn try_from(select: rnix::ast::Select) -> Result<Self, Self::Error> {
|
|
Ok(Self {
|
|
receiver: select.expr().ok_or(())?.try_into()?,
|
|
attrs: select
|
|
.attrpath()
|
|
.ok_or(())?
|
|
.attrs()
|
|
.map(|attr| match attr {
|
|
rnix::ast::Attr::Ident(ident) => Ok(ident.into()),
|
|
_ => Err(()),
|
|
})
|
|
.collect::<Result<Vec<_>, _>>()?,
|
|
})
|
|
}
|
|
}
|
|
|
|
fn convert_inherit(node: rnix::SyntaxNode) -> Option<ast::Node> {
|
|
let inherit = rnix::ast::Inherit::cast(node)?;
|
|
|
|
Some(ast::Node {
|
|
range: inherit.syntax().text_range().into(),
|
|
data: ast::NodeData::Inherit(inherit.into()),
|
|
})
|
|
}
|
|
|
|
impl From<rnix::ast::Inherit> for ast::Inherit {
|
|
fn from(inherit: rnix::ast::Inherit) -> Self {
|
|
Self {
|
|
attr_count: inherit.attrs().count(),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn convert_token(token: rnix::SyntaxToken) -> Option<ast::Token> {
|
|
match token.kind() {
|
|
rnix::SyntaxKind::TOKEN_URI => Some(ast::Token {
|
|
range: token.text_range().into(),
|
|
data: ast::TokenData::UnquotedUri(token.text().to_string()),
|
|
}),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn convert_parse_error(error: &rnix::ParseError, source_len: usize) -> ast::ParseError {
|
|
ast::ParseError {
|
|
range: parse_error_range(error, source_len),
|
|
message: error.to_string(),
|
|
}
|
|
}
|
|
|
|
fn parse_error_range(error: &rnix::ParseError, source_len: usize) -> ast::SourceRange {
|
|
match error {
|
|
rnix::ParseError::Unexpected(range)
|
|
| rnix::ParseError::UnexpectedExtra(range)
|
|
| rnix::ParseError::UnexpectedWanted(_, range, _)
|
|
| rnix::ParseError::UnexpectedDoubleBind(range)
|
|
| rnix::ParseError::DuplicatedArgs(range, _) => (*range).into(),
|
|
|
|
rnix::ParseError::UnexpectedEOF
|
|
| rnix::ParseError::UnexpectedEOFWanted(_)
|
|
| rnix::ParseError::RecursionLimitExceeded => ast::SourceRange {
|
|
start: source_len,
|
|
end: source_len,
|
|
},
|
|
|
|
_ => ast::SourceRange {
|
|
start: source_len,
|
|
end: source_len,
|
|
},
|
|
}
|
|
}
|
|
|
|
impl From<rnix::TextRange> for ast::SourceRange {
|
|
fn from(range: rnix::TextRange) -> Self {
|
|
Self {
|
|
start: usize::from(range.start()),
|
|
end: usize::from(range.end()),
|
|
}
|
|
}
|
|
}
|