mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 18:58:30 +00:00
feat: add ASTDiff
and impl lazy compilation
This commit is contained in:
parent
cac2c51cd4
commit
33e1b776cb
9 changed files with 140 additions and 7 deletions
|
@ -77,9 +77,9 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
return Ok(());
|
||||
};
|
||||
let mut parser = Parser::new(ts);
|
||||
if parser.parse().is_err() {
|
||||
let Ok(module) = parser.parse() else {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let path = util::uri_to_path(&uri);
|
||||
let code = self.file_cache.get_entire_code(&uri)?;
|
||||
let mode = if path.to_string_lossy().ends_with(".d.er") {
|
||||
|
@ -87,6 +87,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
} else {
|
||||
"exec"
|
||||
};
|
||||
if let Some(mut lowerer) = self.get_lowerer(&path) {}
|
||||
let mut checker = self.get_checker(path);
|
||||
match checker.build(code, mode) {
|
||||
Ok(artifact) => {
|
||||
|
|
93
crates/els/diff.rs
Normal file
93
crates/els/diff.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
use std::cmp::Ordering::*;
|
||||
|
||||
use erg_common::traits::Stream;
|
||||
use erg_compiler::erg_parser::ast;
|
||||
use erg_compiler::erg_parser::ast::AST;
|
||||
use erg_compiler::hir;
|
||||
use erg_compiler::hir::HIR;
|
||||
use erg_compiler::lower::ASTLowerer;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ASTDiff {
|
||||
Deletion(usize),
|
||||
Addition(usize, ast::Expr),
|
||||
Modification(usize, ast::Expr),
|
||||
Nop,
|
||||
}
|
||||
|
||||
/// diff(old: {x, y, z}, new: {x, a, y, z}) => ASTDiff::Addition(1)
|
||||
/// diff(old: {x, y}, new: {x, y, a}) => ASTDiff::Addition(2)
|
||||
/// diff(old: {x, y}, new: {x}) => ASTDiff::Deletion(1)
|
||||
/// diff(old: {x, y, z}, new: {x, z}) => ASTDiff::Deletion(1)
|
||||
/// diff(old: {x, y, z}, new: {x, ya, z}) => ASTDiff::Modification(1)
|
||||
/// diff(old: {x, y, z}, new: {x, a, z}) => ASTDiff::Modification(1)
|
||||
/// diff(old: {x, y, z}, new: {x, y, z}) => ASTDiff::Nop
|
||||
impl ASTDiff {
|
||||
pub fn diff(old: AST, new: AST) -> ASTDiff {
|
||||
match old.module.len().cmp(&new.module.len()) {
|
||||
Less => {
|
||||
let idx = new
|
||||
.module
|
||||
.iter()
|
||||
.zip(old.module.iter())
|
||||
.position(|(new, old)| new != old)
|
||||
.unwrap();
|
||||
Self::Addition(idx, new.module.get(idx).unwrap().clone())
|
||||
}
|
||||
Greater => Self::Deletion(
|
||||
old.module
|
||||
.iter()
|
||||
.zip(new.module.iter())
|
||||
.position(|(old, new)| old != new)
|
||||
.unwrap(),
|
||||
),
|
||||
Equal => old
|
||||
.module
|
||||
.iter()
|
||||
.zip(new.module.iter())
|
||||
.position(|(old, new)| old != new)
|
||||
.map(|idx| Self::Modification(idx, new.module.get(idx).unwrap().clone()))
|
||||
.unwrap_or(Self::Nop),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum HIRDiff {
|
||||
Deletion(usize),
|
||||
Addition(usize, hir::Expr),
|
||||
Modification(usize, hir::Expr),
|
||||
Nop,
|
||||
}
|
||||
|
||||
impl HIRDiff {
|
||||
pub fn new(diff: ASTDiff, lowerer: &mut ASTLowerer) -> Option<Self> {
|
||||
match diff {
|
||||
ASTDiff::Deletion(idx) => Some(Self::Deletion(idx)),
|
||||
ASTDiff::Addition(idx, expr) => {
|
||||
let expr = lowerer.lower_expr(expr).ok()?;
|
||||
Some(Self::Addition(idx, expr))
|
||||
}
|
||||
ASTDiff::Modification(idx, expr) => {
|
||||
let expr = lowerer.lower_expr(expr).ok()?;
|
||||
Some(Self::Modification(idx, expr))
|
||||
}
|
||||
ASTDiff::Nop => Some(Self::Nop),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(self, old: &mut HIR) {
|
||||
match self {
|
||||
Self::Addition(idx, expr) => {
|
||||
old.module.insert(idx, expr);
|
||||
}
|
||||
Self::Deletion(usize) => {
|
||||
old.module.remove(usize);
|
||||
}
|
||||
Self::Modification(idx, expr) => {
|
||||
*old.module.get_mut(idx).unwrap() = expr;
|
||||
}
|
||||
Self::Nop => {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,9 +38,9 @@ pub struct FileCacheEntry {
|
|||
|
||||
impl FileCacheEntry {
|
||||
/// line: 0-based
|
||||
pub fn get_line(&self, line: u32) -> Option<String> {
|
||||
pub fn get_line(&self, line0: u32) -> Option<String> {
|
||||
let mut lines = self.code.lines();
|
||||
lines.nth(line as usize).map(|s| s.to_string())
|
||||
lines.nth(line0 as usize).map(|s| s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,9 +164,9 @@ impl FileCache {
|
|||
}
|
||||
|
||||
/// 0-based
|
||||
pub(crate) fn get_line(&self, uri: &NormalizedUrl, line: u32) -> Option<String> {
|
||||
pub(crate) fn get_line(&self, uri: &NormalizedUrl, line0: u32) -> Option<String> {
|
||||
let _ = self.load_once(uri);
|
||||
self.files.borrow_mut().get(uri)?.get_line(line)
|
||||
self.files.borrow_mut().get(uri)?.get_line(line0)
|
||||
}
|
||||
|
||||
pub(crate) fn get_ranged(
|
||||
|
|
|
@ -4,6 +4,7 @@ mod command;
|
|||
mod completion;
|
||||
mod definition;
|
||||
mod diagnostics;
|
||||
mod diff;
|
||||
mod file_cache;
|
||||
mod hir_visitor;
|
||||
mod hover;
|
||||
|
|
|
@ -4,6 +4,7 @@ mod command;
|
|||
mod completion;
|
||||
mod definition;
|
||||
mod diagnostics;
|
||||
mod diff;
|
||||
mod file_cache;
|
||||
mod hir_visitor;
|
||||
mod hover;
|
||||
|
|
|
@ -3,9 +3,12 @@ use std::io;
|
|||
use std::io::{stdin, stdout, BufRead, Read, StdinLock, StdoutLock, Write};
|
||||
use std::ops::Not;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
|
||||
use erg_common::consts::PYTHON_MODE;
|
||||
use erg_compiler::error::{CompileErrors, CompileWarnings};
|
||||
use erg_compiler::lower::ASTLowerer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use serde_json::Value;
|
||||
|
@ -538,6 +541,21 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_lowerer(&self, path: &Path) -> Option<ASTLowerer> {
|
||||
let module = Rc::get_mut(&mut self.get_shared().unwrap().mod_cache.get_mut(path)?.module)?;
|
||||
let module = std::mem::take(module);
|
||||
Some(ASTLowerer::new_with_ctx(module))
|
||||
}
|
||||
|
||||
pub(crate) fn restore_mod_ctx(&self, path: &Path, module: ModuleContext) {
|
||||
self.get_shared()
|
||||
.unwrap()
|
||||
.mod_cache
|
||||
.get_mut(path)
|
||||
.unwrap()
|
||||
.module = Rc::new(module);
|
||||
}
|
||||
|
||||
pub(crate) fn get_visitor(&self, uri: &NormalizedUrl) -> Option<HIRVisitor> {
|
||||
self.artifacts
|
||||
.get(uri)?
|
||||
|
|
|
@ -351,6 +351,12 @@ macro_rules! impl_stream {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::ops::IndexMut<usize> for $Strc {
|
||||
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
|
||||
erg_common::traits::Stream::get_mut(self, idx).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$Strc> for Vec<$Inner> {
|
||||
fn from(item: $Strc) -> Vec<$Inner> {
|
||||
item.payload()
|
||||
|
|
|
@ -1179,4 +1179,8 @@ impl ModuleContext {
|
|||
scope,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_top_cfg(&self) -> ErgConfig {
|
||||
self.context.cfg.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,6 +175,15 @@ impl ASTLowerer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_with_ctx(module: ModuleContext) -> Self {
|
||||
Self {
|
||||
cfg: module.get_top_cfg(),
|
||||
module,
|
||||
errs: LowerErrors::empty(),
|
||||
warns: LowerWarnings::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_append_errs(&mut self) {
|
||||
match self.module.context.check_decls_and_pop() {
|
||||
Ok(ctx) if self.cfg.mode == ErgMode::LanguageServer && !ctx.dir().is_empty() => {
|
||||
|
@ -2307,7 +2316,7 @@ impl ASTLowerer {
|
|||
|
||||
// Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments)
|
||||
// so turn off type checking (check=false)
|
||||
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
|
||||
pub fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
|
||||
log!(info "entered {}", fn_name!());
|
||||
match expr {
|
||||
ast::Expr::Literal(lit) => Ok(hir::Expr::Lit(self.lower_literal(lit)?)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue