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
@@ -0,0 +1,84 @@
//! 标准库:corelen, typeof, push, pop
use crate::error::RuntimeError;
use crate::interpreter::{Interpreter, Value};
pub fn len(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
if args.is_empty() {
return Err(RuntimeError::RuntimeError {
message: "len() expects 1 argument".into(),
token: None,
});
}
match &args[0] {
Value::String(s) => Ok(Value::Number(s.chars().count() as f64)),
Value::Array(arr) => Ok(Value::Number(arr.borrow().len() as f64)),
Value::Object(obj) => Ok(Value::Number(obj.borrow().len() as f64)),
_ => Err(RuntimeError::RuntimeError {
message: "len() expects a string, array, or object".into(),
token: None,
}),
}
}
pub fn typeof_fn(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
if args.is_empty() {
return Err(RuntimeError::RuntimeError {
message: "typeof() expects 1 argument".into(),
token: None,
});
}
let s = match &args[0] {
Value::Number(_) => "number",
Value::String(_) => "string",
Value::Bool(_) => "bool",
Value::Nil => "nil",
Value::Object(_) => "object",
Value::Array(_) => "array",
Value::Function(_) => "function",
Value::NativeFunction(_) => "native_function",
};
Ok(Value::String(s.into()))
}
pub fn push(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
if args.len() < 2 {
return Err(RuntimeError::RuntimeError {
message: "push() expects 2 arguments (array, value)".into(),
token: None,
});
}
let val = args[1].clone();
match &args[0] {
Value::Array(arr) => {
arr.borrow_mut().push(val.clone());
Ok(val)
}
_ => Err(RuntimeError::RuntimeError {
message: "push() expects an array as first argument".into(),
token: None,
}),
}
}
pub fn pop(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, RuntimeError> {
if args.is_empty() {
return Err(RuntimeError::RuntimeError {
message: "pop() expects 1 argument (array)".into(),
token: None,
});
}
match &args[0] {
Value::Array(arr) => arr
.borrow_mut()
.pop()
.ok_or_else(|| RuntimeError::RuntimeError {
message: "pop() on empty array".into(),
token: None,
}),
_ => Err(RuntimeError::RuntimeError {
message: "pop() expects an array as first argument".into(),
token: None,
}),
}
}