Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nls/src/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod completion;
pub mod flow;
pub mod generics;
pub mod global_eval;
pub mod interface;
pub mod lexer; // 声明子模块
pub mod semantic;
pub mod symbol;
Expand Down
50 changes: 47 additions & 3 deletions nls/src/analyzer/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub struct Type {
pub status: ReductionStatus,
pub start: usize, // 类型定义开始位置
pub end: usize, // 类型定义结束位置
pub storage_kind: StorageKind,
pub in_heap: bool,
pub err: bool,
}
Expand All @@ -82,6 +83,7 @@ impl Default for Type {
ident_kind: TypeIdentKind::Unknown,
start: 0,
end: 0,
storage_kind: StorageKind::Ptr,
in_heap: false,
err: false,
}
Expand Down Expand Up @@ -125,6 +127,7 @@ impl Type {
status: ReductionStatus::Done,
start: 0,
end: 0,
storage_kind: Self::storage_kind(&kind),
in_heap: Self::kind_in_heap(&kind),
err: false,
};
Expand All @@ -149,6 +152,7 @@ impl Type {
status: ReductionStatus::Undo,
start: 0,
end: 0,
storage_kind: StorageKind::Ptr,
in_heap: false,
err: false,
}
Expand All @@ -165,6 +169,7 @@ impl Type {
status: ReductionStatus::Undo,
start: 0,
end: 0,
storage_kind: Self::storage_kind(&kind),
in_heap: Self::kind_in_heap(&kind),
err: false,
}
Expand Down Expand Up @@ -235,7 +240,8 @@ impl Type {
"tup<...>".to_string()
}
TypeKind::Fn(type_fn) => {
format!("fn(...):{}{}", type_fn.return_type, if type_fn.errable { "!" } else { "" })
let fn_prefix = if type_fn.fx { "fx" } else { "fn" };
format!("{}(...):{}{}", fn_prefix, type_fn.return_type, if type_fn.errable { "!" } else { "" })
}
TypeKind::Ref(value_type) => {
format!("ref<{}>", value_type)
Expand Down Expand Up @@ -320,6 +326,30 @@ impl Type {
Self::is_integer(kind) || Self::is_float(kind)
}

pub fn storage_kind(kind: &TypeKind) -> StorageKind {
if Self::is_number(kind) || matches!(kind, TypeKind::Bool | TypeKind::Anyptr | TypeKind::Enum(..) | TypeKind::Void) {
return StorageKind::Dir;
}

if matches!(
kind,
TypeKind::String
| TypeKind::Vec(..)
| TypeKind::Map(..)
| TypeKind::Set(..)
| TypeKind::Struct(..)
| TypeKind::Arr(..)
| TypeKind::Union(..)
| TypeKind::Tuple(..)
| TypeKind::TaggedUnion(..)
| TypeKind::Interface(..)
) {
return StorageKind::Ind;
}

return StorageKind::Ptr;
}

pub fn is_any(kind: &TypeKind) -> bool {
let TypeKind::Union(any, _, _) = kind else {
return false;
Expand Down Expand Up @@ -422,7 +452,6 @@ impl Type {
| TypeKind::String
| TypeKind::Set(..)
| TypeKind::Map(..)
| TypeKind::Tuple(..)
| TypeKind::Union(..)
| TypeKind::TaggedUnion(..)
)
Expand All @@ -446,6 +475,7 @@ impl Type {
pub fn integer_t_new() -> Type {
let mut t = Type::new(TypeKind::Ident);
t.kind = Self::cross_kind_trans(&TypeKind::Int);
t.storage_kind = Self::storage_kind(&t.kind);
t.ident = TypeKind::IntegerT.to_string();
t.ident_kind = TypeIdentKind::Builtin;
return t;
Expand All @@ -457,6 +487,7 @@ impl Type {
let mut ptr_type = Type::new(ptr_kind);
ptr_type.start = t.start;
ptr_type.end = t.end;
ptr_type.storage_kind = StorageKind::Ptr;
ptr_type.in_heap = false;
return ptr_type;
}
Expand All @@ -469,6 +500,7 @@ impl Type {
let mut ptr_type = Type::new(ptr_kind);
ptr_type.start = t.start;
ptr_type.end = t.end;
ptr_type.storage_kind = StorageKind::Ptr;
ptr_type.in_heap = false;
return ptr_type;
}
Expand Down Expand Up @@ -520,7 +552,7 @@ impl Type {
}
TypeKind::Fn(type_fn) => {
let mut hasher = DefaultHasher::new();
let mut str = self.kind.to_string();
let mut str = if type_fn.fx { "fx".to_string() } else { self.kind.to_string() };
str = format!("{}.{}", str, type_fn.return_type.hash());
for param_type in &type_fn.param_types {
str = format!("{}_{}", str, param_type.hash());
Expand Down Expand Up @@ -610,6 +642,7 @@ pub struct TypeFn {
pub param_types: Vec<Type>,
pub errable: bool,
pub rest: bool,
pub fx: bool,
pub tpl: bool,
}

Expand Down Expand Up @@ -675,6 +708,13 @@ pub enum TypeIdentKind {
TaggedUnion, // tagged union type
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StorageKind {
Dir,
Ind,
Ptr,
}

#[derive(Debug, Clone, Display)]
#[repr(u8)]
pub enum TypeKind {
Expand Down Expand Up @@ -959,6 +999,7 @@ pub enum AstNode {
VarTupleDestr(Vec<Box<Expr>>, Box<Expr>), // (elements, right)
Assign(Box<Expr>, Box<Expr>), // (left, right)
Return(Option<Box<Expr>>), // (expr)
Defer(AstBody), // body
If(Box<Expr>, AstBody, AstBody), // (condition, consequent, alternate)
Throw(Box<Expr>),
TryCatch(AstBody, Arc<Mutex<VarDeclExpr>>, AstBody), // (try_body, catch_err, catch_body)
Expand Down Expand Up @@ -1068,6 +1109,7 @@ pub struct AstCall {
pub generics_args: Vec<Type>,
pub args: Vec<Box<Expr>>,
pub spread: bool,
pub inject_self_arg: bool,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -1247,6 +1289,7 @@ pub struct AstFnDef {
pub is_generics: bool,
pub is_async: bool,
pub is_private: bool,
pub is_fx: bool,
pub is_errable: bool, // 当前函数是否返回错误
pub is_test: bool,
pub test_name: String,
Expand Down Expand Up @@ -1300,6 +1343,7 @@ impl Default for AstFnDef {
is_generics: false,
is_async: false,
is_private: false,
is_fx: false,
is_errable: false,
is_test: false,
test_name: "".to_string(),
Expand Down
3 changes: 2 additions & 1 deletion nls/src/analyzer/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,8 @@ impl<'a> CompletionProvider<'a> {
}

let return_type = fndef.return_type.to_string();
format!("fn({}): {}", params_str, return_type)
let fn_prefix = if fndef.is_fx { "fx" } else { "fn" };
format!("{}({}): {}", fn_prefix, params_str, return_type)
}

/// Find innermost scope containing the position starting from module scope
Expand Down
47 changes: 31 additions & 16 deletions nls/src/analyzer/generics.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::collections::HashSet;

use super::common::{
AnalyzerError, AstBody, AstCall, AstFnDef, AstNode, Expr, ExprOp, GenericsParam, MacroArg, MatchCase, SelectCase, Stmt, Type, TypeIdentKind, TypeKind,
AnalyzerError, AstBody, AstCall, AstFnDef, AstNode, Expr, ExprOp, GenericsParam, MacroArg, MatchCase, SelectCase, Stmt, Type, TypeFn, TypeIdentKind,
TypeKind,
};
use super::symbol::{SymbolKind, SymbolTable};
use crate::project::Module;
Expand Down Expand Up @@ -102,58 +103,58 @@ impl<'a> Generics<'a> {
false
}

fn interface_declares_method(&self, interface_type: &Type, method_name: &str, visited: &mut HashSet<String>) -> bool {
fn interface_declares_method(&self, interface_type: &Type, method_name: &str, visited: &mut HashSet<String>) -> Option<Box<TypeFn>> {
if let TypeKind::Interface(elements) = &interface_type.kind {
for element in elements {
if let TypeKind::Fn(type_fn) = &element.kind {
if type_fn.name == method_name {
return true;
return Some(type_fn.clone());
}
}
}
}

if interface_type.ident.is_empty() {
return false;
return None;
}
if !visited.insert(interface_type.ident.clone()) {
return false;
return None;
}

let Some(symbol) = self.symbol_table.find_global_symbol(&interface_type.ident) else {
return false;
return None;
};
let SymbolKind::Type(typedef_mutex) = &symbol.kind else {
return false;
return None;
};
let typedef_stmt = typedef_mutex.lock().unwrap();

if let TypeKind::Interface(elements) = &typedef_stmt.type_expr.kind {
for element in elements {
if let TypeKind::Fn(type_fn) = &element.kind {
if type_fn.name == method_name {
return true;
return Some(type_fn.clone());
}
}
}
}

for impl_interface in &typedef_stmt.impl_interfaces {
if self.interface_declares_method(impl_interface, method_name, visited) {
return true;
if let Some(method) = self.interface_declares_method(impl_interface, method_name, visited) {
return Some(method);
}
}

false
None
}

fn constraint_has_method(&self, param: &GenericsParam, method_name: &str) -> bool {
fn constraint_has_method(&self, param: &GenericsParam, method_name: &str) -> Option<Box<TypeFn>> {
for constraint in &param.constraints {
if self.interface_declares_method(constraint, method_name, &mut HashSet::new()) {
return true;
if let Some(method) = self.interface_declares_method(constraint, method_name, &mut HashSet::new()) {
return Some(method);
}
}
false
None
}

fn check_bool_operand(&mut self, fndef: &AstFnDef, expr: &Expr) {
Expand Down Expand Up @@ -269,12 +270,25 @@ impl<'a> Generics<'a> {
return;
}

if !self.constraint_has_method(param, key) {
let Some(found_method) = self.constraint_has_method(param, key) else {
self.push_error(
call.left.start,
call.left.end,
format!("generic param '{}' has no constraint declaring fn '{}'", generic_param_ident, key),
);
return;
};

if !found_method.tpl && !call.generics_args.is_empty() {
self.push_error(
call.left.start,
call.left.end,
format!(
"method '{}' has no generic parameters, but {} generic args provided",
key,
call.generics_args.len()
),
);
}
}

Expand Down Expand Up @@ -449,6 +463,7 @@ impl<'a> Generics<'a> {
}
AstNode::Ret(expr) => self.check_expr(fndef, expr),
AstNode::Throw(error_expr) => self.check_expr(fndef, error_expr),
AstNode::Defer(body) => self.check_body(fndef, body),
AstNode::Catch(try_expr, _, catch_body) => {
self.check_expr(fndef, try_expr);
self.check_body(fndef, catch_body);
Expand Down
Loading
Loading