Switch to use our custom parser

This commit is contained in:
oxalica 2022-07-24 05:13:56 +08:00
parent d3b30a688a
commit d0132c886c
6 changed files with 72 additions and 151 deletions

29
Cargo.lock generated
View file

@ -14,15 +14,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29b6ad25ae296159fb0da12b970b2fe179b234584d7cd294c891e2bbb284466b"
dependencies = [
"num-traits",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -146,19 +137,10 @@ version = "0.0.0"
dependencies = [
"expect-test",
"la-arena",
"rnix",
"rowan",
"salsa",
"smol_str",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
"syntax",
]
[[package]]
@ -241,15 +223,6 @@ version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "rnix"
version = "0.11.0-dev"
source = "git+https://github.com/oxalica/rnix-parser.git#80fabb304defc3b488f21d225128bde0758d1eb3"
dependencies = [
"cbitset",
"rowan",
]
[[package]]
name = "rowan"
version = "0.15.6"

View file

@ -5,11 +5,12 @@ edition = "2021"
[dependencies]
la-arena = "0.2.1"
rnix = { git = "https://github.com/oxalica/rnix-parser.git" }
rowan = "0.15.6"
salsa = "0.17.0-pre.2"
smol_str = "0.1.23"
syntax = { path = "./syntax" }
[dev-dependencies]
expect-test = "1.3.0"

View file

@ -1,17 +1,15 @@
use super::{AstPtr, Expr, ExprId, Literal, Module, ModuleSourceMap, Path, PathAnchor};
use super::{AstPtr, Expr, ExprId, Literal, Module, ModuleSourceMap};
use crate::source::{FileId, InFile};
use rnix::types::{ParsedType, Root, TokenWrapper, TypedNode, Wrapper};
use rnix::value::Anchor;
use rnix::{NixValue, SyntaxNode, AST};
use rowan::ast::AstNode;
use syntax::ast::{self, LiteralKind};
pub(super) fn lower(ast: InFile<AST>) -> (Module, ModuleSourceMap) {
pub(super) fn lower(root: InFile<ast::SourceFile>) -> (Module, ModuleSourceMap) {
let mut ctx = LowerCtx {
file_id: ast.file_id,
file_id: root.file_id,
module: Module::default(),
source_map: ModuleSourceMap::default(),
};
let node = Root::cast(ast.value.node()).map(|root| root.node().clone());
ctx.lower_node_opt(node);
ctx.lower_expr_opt(root.value.expr());
(ctx.module, ctx.source_map)
}
@ -29,83 +27,60 @@ impl LowerCtx {
id
}
fn lower_node_opt(&mut self, node: Option<SyntaxNode>) -> ExprId {
if let Some(node) = node {
if let Ok(expr) = ParsedType::try_from(node) {
return self.lower_expr(expr);
}
fn lower_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
if let Some(expr) = expr {
return self.lower_expr(expr);
}
// Synthetic syntax has no coresponding text.
self.module.exprs.alloc(Expr::Missing)
}
fn lower_path(&mut self, anchor: Anchor, segments: &str, ptr: AstPtr) -> ExprId {
let anchor = match anchor {
Anchor::Relative => PathAnchor::Relative(self.file_id),
Anchor::Absolute => todo!(),
Anchor::Home => todo!(),
Anchor::Store => todo!(),
};
let path = Path {
anchor,
raw_segments: segments.into(),
};
self.alloc_expr(Expr::Literal(Literal::Path(path)), ptr)
fn lower_expr(&mut self, expr: ast::Expr) -> ExprId {
let ptr = AstPtr::new(expr.syntax());
match expr {
ast::Expr::Literal(e) => {
let lit = self.lower_literal(e);
self.alloc_expr(lit.map_or(Expr::Missing, Expr::Literal), ptr)
}
ast::Expr::Name(e) => {
let name = e.token().map_or_else(|| "".into(), |tok| tok.text().into());
self.alloc_expr(Expr::Ident(name), ptr)
}
ast::Expr::Apply(e) => {
let func = self.lower_expr_opt(e.function());
let arg = self.lower_expr_opt(e.argument());
self.alloc_expr(Expr::Apply(func, arg), ptr)
}
ast::Expr::Paren(e) => self.lower_expr_opt(e.expr()),
ast::Expr::Assert(_) => todo!(),
ast::Expr::AttrSet(_) => todo!(),
ast::Expr::BinaryOp(_) => todo!(),
ast::Expr::HasAttr(_) => todo!(),
ast::Expr::IfThenElse(_) => todo!(),
ast::Expr::IndentString(_) => todo!(),
ast::Expr::Lambda(_) => todo!(),
ast::Expr::LetIn(_) => todo!(),
ast::Expr::List(_) => todo!(),
ast::Expr::Select(_) => todo!(),
ast::Expr::String(_) => todo!(),
ast::Expr::UnaryOp(_) => todo!(),
ast::Expr::With(_) => todo!(),
}
}
fn lower_expr(&mut self, expr: ParsedType) -> ExprId {
let ptr = AstPtr::new(expr.node());
let expr = match expr {
ParsedType::Root(e) => return self.lower_node_opt(e.inner()),
ParsedType::Paren(e) => return self.lower_node_opt(e.inner()),
ParsedType::Ident(e) => {
let ident = e.to_inner_string();
Expr::Ident(ident.into())
}
ParsedType::Value(e) => match e.to_value() {
Ok(v) => {
let lit = match v {
NixValue::Integer(x) => Literal::Int(x),
NixValue::Float(_) => todo!(),
NixValue::String(s) => Literal::String(s.into()),
NixValue::Path(anchor, path) => return self.lower_path(anchor, &path, ptr),
};
Expr::Literal(lit)
}
Err(_) => Expr::Missing,
},
ParsedType::Apply(e) => {
let lam = self.lower_node_opt(e.lambda());
let arg = self.lower_node_opt(e.value());
Expr::Apply(lam, arg)
}
ParsedType::Assert(_) => todo!(),
ParsedType::IfElse(_) => todo!(),
ParsedType::Select(_) => todo!(),
ParsedType::Inherit(_) => todo!(),
ParsedType::InheritFrom(_) => todo!(),
ParsedType::Lambda(_) => todo!(),
ParsedType::LegacyLet(_) => todo!(),
ParsedType::LetIn(_) => todo!(),
ParsedType::List(_) => todo!(),
ParsedType::BinOp(_) => todo!(),
ParsedType::OrDefault(_) => todo!(),
ParsedType::AttrSet(_) => todo!(),
ParsedType::KeyValue(_) => todo!(),
ParsedType::Str(_) => todo!(),
ParsedType::StrInterpol(_) => todo!(),
ParsedType::UnaryOp(_) => todo!(),
ParsedType::With(_) => todo!(),
ParsedType::PathWithInterpol(_) => todo!(),
fn lower_literal(&mut self, lit: ast::Literal) -> Option<Literal> {
let kind = lit.kind()?;
let tok = lit.token().unwrap();
let text = tok.text();
// Invalid nodes in expression location.
ParsedType::Pattern(_)
| ParsedType::PatBind(_)
| ParsedType::PatEntry(_)
| ParsedType::Key(_)
| ParsedType::Dynamic(_)
| ParsedType::Error(_) => Expr::Missing,
};
self.alloc_expr(expr, ptr)
Some(match kind {
LiteralKind::Int => Literal::Int(text.parse::<i64>().ok()?),
LiteralKind::Float => todo!(),
LiteralKind::Uri => Literal::String(text.into()),
LiteralKind::RelativePath => todo!(),
LiteralKind::AbsolutePath => todo!(),
LiteralKind::HomePath => todo!(),
LiteralKind::SearchPath => todo!(),
})
}
}

View file

@ -23,8 +23,8 @@ fn module_with_source_map(
db: &dyn DefDatabase,
file_id: FileId,
) -> (Arc<Module>, Arc<ModuleSourceMap>) {
let root = db.parse(file_id);
let (module, source_map) = lower::lower(root);
let parse = db.parse(file_id);
let (module, source_map) = lower::lower(parse.map(|p| p.root()));
(Arc::new(module), Arc::new(source_map))
}
@ -50,7 +50,7 @@ impl ops::Index<ExprId> for Module {
}
}
pub type AstPtr = rowan::ast::SyntaxNodePtr<rnix::NixLanguage>;
pub type AstPtr = rowan::ast::SyntaxNodePtr<syntax::NixLanguage>;
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct ModuleSourceMap {

View file

@ -4,15 +4,11 @@ use expect_test::expect;
#[test]
fn module_basic() {
let (db, root_id) = TestDB::from_file(
r#"
foo 123 ./bar.nix
"#,
);
let (db, root_id) = TestDB::from_file("foo 123");
expect![[r#"
Module {
exprs: Arena {
len: 5,
len: 3,
data: [
Ident(
Name(
@ -28,22 +24,6 @@ fn module_basic() {
Idx::<Expr>(0),
Idx::<Expr>(1),
),
Literal(
Path(
Path {
anchor: Relative(
FileId(
0,
),
),
raw_segments: "./bar.nix",
},
),
),
Apply(
Idx::<Expr>(2),
Idx::<Expr>(3),
),
],
},
}
@ -57,24 +37,16 @@ fn module_basic() {
expect![[r#"
[
SyntaxNodePtr {
kind: NODE_IDENT,
range: 9..12,
kind: NAME,
range: 0..3,
},
SyntaxNodePtr {
kind: NODE_LITERAL,
range: 13..16,
kind: LITERAL,
range: 4..7,
},
SyntaxNodePtr {
kind: NODE_APPLY,
range: 9..16,
},
SyntaxNodePtr {
kind: NODE_LITERAL,
range: 17..26,
},
SyntaxNodePtr {
kind: NODE_APPLY,
range: 9..26,
kind: APPLY,
range: 0..7,
},
]
"#]]

View file

@ -1,5 +1,5 @@
use rnix::AST;
use std::sync::Arc;
use syntax::Parse;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FileId(pub u32);
@ -31,12 +31,12 @@ pub trait SourceDatabase {
#[salsa::input]
fn file_content(&self, file_id: FileId) -> Arc<[u8]>;
fn parse(&self, file_id: FileId) -> InFile<AST>;
fn parse(&self, file_id: FileId) -> InFile<Parse>;
}
fn parse(db: &dyn SourceDatabase, file_id: FileId) -> InFile<AST> {
fn parse(db: &dyn SourceDatabase, file_id: FileId) -> InFile<Parse> {
let content = db.file_content(file_id);
let content = std::str::from_utf8(&content).unwrap_or_default();
let ast = rnix::parse(content);
InFile::new(file_id, ast)
let parse = syntax::parse_file(content);
InFile::new(file_id, parse)
}