feat: IDE支持 — workspace拆分、LSP服务器、VS Code扩展

**Workspace 拆分**
- aster-core: 纯库,zero-dependency,包含 lexer/parser/ast/interpreter/error/analysis
- aster: REPL 二进制,薄封装 aster-core
- aster-lsp: LSP 语言服务器

**VS Code 扩展 (vscode-ext/)**
- TextMate 语法高亮 (.ast 文件)
- 语言配置 (注释切换、括号配对、自动缩进)
- LSP 客户端 (extension.js)

**LSP 服务端功能**
- Diagnostics: 实时显示 lex/parse 错误红色波浪线
- Completion: 关键字 + 内置函数 + 用户定义符号补全
- Hover: 悬停显示变量/函数信息
- Signature Help: 函数参数提示
- Goto Definition: Ctrl+Click 跳转到声明处
- Find References: 查找所有引用位置
- Rename: F2 重命名符号

**新增 analysis 模块**
- collect_symbols: AST 遍历收集符号
- find_declaration/find_all_references: Token 扫描定位声明和引用
This commit is contained in:
2026-06-25 00:28:13 +08:00
parent 99c9e9c9bd
commit bdffe9e3c5
65 changed files with 1709 additions and 47 deletions
+140
View File
@@ -0,0 +1,140 @@
//! 模块系统:require() 加载器
//!
//! `require("path/to/module.ast")` 加载并执行指定的 Aster 文件,
//! 返回一个包含模块所有顶层定义的 `Value::Object`。
//! 模块在自己的作用域中执行,只能访问内置函数,无法访问调用者的变量。
//! 第二次 require 同一文件会返回缓存的对象。
use crate::error::RuntimeError;
use crate::lexer::Lexer;
use crate::parser::Parser;
use super::{Interpreter, Env, Value, Signal};
use std::cell::RefCell;
use std::collections::HashMap;
use std::path::Path;
use std::rc::Rc;
/// require() 的内置函数实现
pub fn require_fn(interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
// 1. 参数验证
let path_str = match args.first() {
Some(Value::String(s)) => s.clone(),
Some(other) => return Err(runtime_error(format!(
"require() expects a string argument, got {}", other))),
None => return Err(runtime_error(
"require() expects 1 argument (string path)")),
};
// 2. 路径解析
let resolved = resolve_path(&interp.current_dir, &path_str)?;
// 3. 缓存查找
if let Some(cached) = interp.module_cache.borrow().get(&resolved) {
return Ok(cached.clone());
}
// 4. 读取文件
let src = std::fs::read_to_string(&resolved)
.map_err(|e| runtime_error(format!(
"Module '{}' not found: {}", path_str, e)))?;
// 5. 词法分析
let (tokens, lex_errors) = Lexer::new(&src).tokenize();
if !lex_errors.is_empty() {
return Err(runtime_error(format!(
"Lex error in module '{}': {}", path_str, lex_errors[0])));
}
// 6. 语法分析
let mut parser = Parser::new(tokens);
let (stmts, parse_errors) = parser.parse();
if !parse_errors.is_empty() {
return Err(runtime_error(format!(
"Parse error in module '{}': {}", path_str, parse_errors[0])));
}
// 7. 创建隔离的模块 env(父级 = builtins_env,看不到调用者的变量)
let module_env = Rc::new(RefCell::new(Env::new(Some(Rc::clone(&interp.builtins_env)))));
// 8. 在缓存中插入占位符(支持循环 require)
let exports_map = Rc::new(RefCell::new(HashMap::new()));
let exports = Value::Object(Rc::clone(&exports_map));
interp.module_cache.borrow_mut().insert(resolved.clone(), exports.clone());
// 9. 保存调用者状态
let previous_env = Rc::clone(&interp.env);
let previous_dir = interp.current_dir.clone();
// 10. 切换到模块上下文
interp.env = module_env.clone();
interp.current_dir = module_dir(&resolved);
// 11. 执行模块
for stmt in &stmts {
match interp.execute(stmt.clone()) {
Ok(Signal::Break) | Ok(Signal::Continue) => {
// 恢复状态后返回错误
interp.env = previous_env;
interp.current_dir = previous_dir;
interp.module_cache.borrow_mut().remove(&resolved);
return Err(runtime_error(
"break/continue outside of loop in module"));
}
Err(e) => {
// 恢复状态后传播错误
interp.env = previous_env;
interp.current_dir = previous_dir;
interp.module_cache.borrow_mut().remove(&resolved);
return Err(e);
}
Ok(Signal::None) | Ok(Signal::Return(_)) => {
// 正常执行或顶层 return,继续
}
}
}
// 12. 恢复调用者状态
interp.env = previous_env;
interp.current_dir = previous_dir;
// 13. 收集 exports(模块 env 中的所有直接绑定)
for (name, (val, _mutable)) in module_env.borrow().values.clone() {
exports_map.borrow_mut().insert(name, val);
}
Ok(exports)
}
// ============================================================================
// Helpers
// ============================================================================
/// 解析模块路径:相对路径基于 current_dir,用 canonicalize 规范化
fn resolve_path(current_dir: &str, path_str: &str) -> Result<String, RuntimeError> {
let path = Path::new(path_str);
let resolved = if path.is_absolute() {
path.to_path_buf()
} else {
Path::new(current_dir).join(path)
};
std::fs::canonicalize(&resolved)
.map(|p| p.to_string_lossy().to_string())
.map_err(|_| runtime_error(format!(
"Module '{}' not found (resolved to '{}')",
path_str, resolved.display())))
}
/// 提取模块文件所在目录
fn module_dir(resolved: &str) -> String {
Path::new(resolved)
.parent()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|| ".".to_string())
}
fn runtime_error(msg: impl Into<String>) -> RuntimeError {
RuntimeError::RuntimeError {
message: msg.into(),
token: None,
}
}