Impl source mapping

This commit is contained in:
oxalica 2022-07-20 00:26:03 +08:00
parent 168a02bbaa
commit 695c54de0c
5 changed files with 77 additions and 34 deletions

1
Cargo.lock generated
View file

@ -141,6 +141,7 @@ dependencies = [
"expect-test",
"la-arena",
"rnix",
"rowan",
"salsa",
]

View file

@ -6,6 +6,7 @@ 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"
[dev-dependencies]

View file

@ -1,34 +1,32 @@
use std::collections::HashSet;
use super::{Expr, ExprId, Literal, Module, ModuleSourceMap, Path, PathAnchor};
use super::{AstPtr, Expr, ExprId, Literal, Module, ModuleSourceMap, Path, PathAnchor};
use crate::source::{FileId, InFile};
use rnix::types::{self as ast, ParsedType, TokenWrapper, TypedNode, Wrapper};
use rnix::types::{ParsedType, Root, TokenWrapper, TypedNode, Wrapper};
use rnix::value::Anchor;
use rnix::{NixValue, SyntaxNode};
use rnix::{NixValue, SyntaxNode, AST};
pub(super) fn lower(root: InFile<ast::Root>) -> (Module, ModuleSourceMap) {
pub(super) fn lower(ast: InFile<AST>) -> (Module, ModuleSourceMap) {
let mut ctx = LowerCtx {
file_id: root.file_id,
file_id: ast.file_id,
module: Module::default(),
paths: HashSet::default(),
source_map: ModuleSourceMap::default(),
};
ctx.lower_node_opt(Some(root.value.node().clone()));
(ctx.module, ModuleSourceMap::default())
let node = Root::cast(ast.value.node()).map(|root| root.node().clone());
ctx.lower_node_opt(node);
(ctx.module, ctx.source_map)
}
struct LowerCtx {
file_id: FileId,
module: Module,
paths: HashSet<Path>,
source_map: ModuleSourceMap,
}
impl LowerCtx {
fn alloc_expr(&mut self, expr: Expr) -> ExprId {
self.module.exprs.alloc(expr)
}
fn alloc_missing(&mut self) -> ExprId {
self.alloc_expr(Expr::Missing)
fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId {
let id = self.module.exprs.alloc(expr);
self.source_map.expr_map.insert(ptr.clone(), id);
self.source_map.expr_map_rev.insert(id, ptr);
id
}
fn lower_node_opt(&mut self, node: Option<SyntaxNode>) -> ExprId {
@ -37,10 +35,11 @@ impl LowerCtx {
return self.lower_expr(expr);
}
}
self.alloc_missing()
// Synthetic syntax has no coresponding text.
self.module.exprs.alloc(Expr::Missing)
}
fn lower_path(&mut self, anchor: Anchor, segments: &str) -> ExprId {
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!(),
@ -51,17 +50,17 @@ impl LowerCtx {
anchor,
raw_segments: segments.into(),
};
self.paths.insert(path.clone());
self.alloc_expr(Expr::Literal(Literal::Path(path)))
self.alloc_expr(Expr::Literal(Literal::Path(path)), ptr)
}
fn lower_expr(&mut self, expr: ParsedType) -> ExprId {
match expr {
ParsedType::Root(e) => self.lower_node_opt(e.inner()),
ParsedType::Paren(e) => self.lower_node_opt(e.inner()),
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();
self.alloc_expr(Expr::Ident(ident.into()))
Expr::Ident(ident.into())
}
ParsedType::Value(e) => match e.to_value() {
Ok(v) => {
@ -69,16 +68,16 @@ impl LowerCtx {
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),
NixValue::Path(anchor, path) => return self.lower_path(anchor, &path, ptr),
};
self.alloc_expr(Expr::Literal(lit))
Expr::Literal(lit)
}
Err(_) => self.alloc_missing(),
Err(_) => Expr::Missing,
},
ParsedType::Apply(e) => {
let lam = self.lower_node_opt(e.lambda());
let arg = self.lower_node_opt(e.value());
self.alloc_expr(Expr::Apply(lam, arg))
Expr::Apply(lam, arg)
}
ParsedType::Assert(_) => todo!(),
ParsedType::IfElse(_) => todo!(),
@ -105,7 +104,8 @@ impl LowerCtx {
| ParsedType::PatEntry(_)
| ParsedType::Key(_)
| ParsedType::Dynamic(_)
| ParsedType::Error(_) => self.alloc_missing(),
}
| ParsedType::Error(_) => Expr::Missing,
};
self.alloc_expr(expr, ptr)
}
}

View file

@ -5,6 +5,7 @@ mod tests;
use crate::source::{FileId, SourceDatabase};
use la_arena::{Arena, Idx};
use std::collections::HashMap;
use std::ops;
use std::sync::Arc;
@ -13,6 +14,8 @@ pub trait DefDatabase: SourceDatabase {
fn module_with_source_map(&self, file_id: FileId) -> (Arc<Module>, Arc<ModuleSourceMap>);
fn module(&self, file_id: FileId) -> Arc<Module>;
fn source_map(&self, file_id: FileId) -> Arc<ModuleSourceMap>;
}
fn module_with_source_map(
@ -20,7 +23,7 @@ fn module_with_source_map(
file_id: FileId,
) -> (Arc<Module>, Arc<ModuleSourceMap>) {
let root = db.parse(file_id);
let (module, source_map) = lower::lower(root.map(|ast| ast.root()));
let (module, source_map) = lower::lower(root);
(Arc::new(module), Arc::new(source_map))
}
@ -28,6 +31,10 @@ fn module(db: &dyn DefDatabase, file_id: FileId) -> Arc<Module> {
db.module_with_source_map(file_id).0
}
fn source_map(db: &dyn DefDatabase, file_id: FileId) -> Arc<ModuleSourceMap> {
db.module_with_source_map(file_id).1
}
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct Module {
exprs: Arena<Expr>,
@ -40,9 +47,13 @@ impl ops::Index<ExprId> for Module {
}
}
// TODO
pub type AstPtr = rowan::ast::SyntaxNodePtr<rnix::NixLanguage>;
#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct ModuleSourceMap {}
pub struct ModuleSourceMap {
expr_map: HashMap<AstPtr, ExprId>,
expr_map_rev: HashMap<ExprId, AstPtr>,
}
pub type ExprId = Idx<Expr>;

View file

@ -48,4 +48,34 @@ fn module_basic() {
}
"#]]
.assert_debug_eq(&db.module(root_id));
let source_map = db.source_map(root_id);
let mut expr_map = source_map.expr_map.iter().collect::<Vec<_>>();
expr_map.sort_by_key(|(_, id)| id.into_raw());
let ptrs = expr_map.iter().map(|(ptr, _)| ptr).collect::<Vec<_>>();
expect![[r#"
[
SyntaxNodePtr {
kind: NODE_IDENT,
range: 9..12,
},
SyntaxNodePtr {
kind: NODE_LITERAL,
range: 13..16,
},
SyntaxNodePtr {
kind: NODE_APPLY,
range: 9..16,
},
SyntaxNodePtr {
kind: NODE_LITERAL,
range: 17..26,
},
SyntaxNodePtr {
kind: NODE_APPLY,
range: 9..26,
},
]
"#]]
.assert_debug_eq(&ptrs);
}