mirror of
https://github.com/oxalica/nil.git
synced 2025-12-23 09:19:49 +00:00
Impl source mapping
This commit is contained in:
parent
168a02bbaa
commit
695c54de0c
5 changed files with 77 additions and 34 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -141,6 +141,7 @@ dependencies = [
|
|||
"expect-test",
|
||||
"la-arena",
|
||||
"rnix",
|
||||
"rowan",
|
||||
"salsa",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue