diff --git a/nls/src/analyzer.rs b/nls/src/analyzer.rs index 4d547d86..9aacaa87 100644 --- a/nls/src/analyzer.rs +++ b/nls/src/analyzer.rs @@ -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; diff --git a/nls/src/analyzer/common.rs b/nls/src/analyzer/common.rs index 67c0bc6b..da1bc944 100644 --- a/nls/src/analyzer/common.rs +++ b/nls/src/analyzer/common.rs @@ -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, } @@ -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, } @@ -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, }; @@ -149,6 +152,7 @@ impl Type { status: ReductionStatus::Undo, start: 0, end: 0, + storage_kind: StorageKind::Ptr, in_heap: false, err: false, } @@ -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, } @@ -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) @@ -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; @@ -422,7 +452,6 @@ impl Type { | TypeKind::String | TypeKind::Set(..) | TypeKind::Map(..) - | TypeKind::Tuple(..) | TypeKind::Union(..) | TypeKind::TaggedUnion(..) ) @@ -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; @@ -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; } @@ -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; } @@ -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()); @@ -610,6 +642,7 @@ pub struct TypeFn { pub param_types: Vec, pub errable: bool, pub rest: bool, + pub fx: bool, pub tpl: bool, } @@ -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 { @@ -959,6 +999,7 @@ pub enum AstNode { VarTupleDestr(Vec>, Box), // (elements, right) Assign(Box, Box), // (left, right) Return(Option>), // (expr) + Defer(AstBody), // body If(Box, AstBody, AstBody), // (condition, consequent, alternate) Throw(Box), TryCatch(AstBody, Arc>, AstBody), // (try_body, catch_err, catch_body) @@ -1068,6 +1109,7 @@ pub struct AstCall { pub generics_args: Vec, pub args: Vec>, pub spread: bool, + pub inject_self_arg: bool, } #[derive(Debug, Clone)] @@ -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, @@ -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(), diff --git a/nls/src/analyzer/completion.rs b/nls/src/analyzer/completion.rs index a31c716d..11572223 100644 --- a/nls/src/analyzer/completion.rs +++ b/nls/src/analyzer/completion.rs @@ -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 diff --git a/nls/src/analyzer/generics.rs b/nls/src/analyzer/generics.rs index d1f4e400..cb75f4ad 100644 --- a/nls/src/analyzer/generics.rs +++ b/nls/src/analyzer/generics.rs @@ -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; @@ -102,29 +103,29 @@ impl<'a> Generics<'a> { false } - fn interface_declares_method(&self, interface_type: &Type, method_name: &str, visited: &mut HashSet) -> bool { + fn interface_declares_method(&self, interface_type: &Type, method_name: &str, visited: &mut HashSet) -> Option> { 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(); @@ -132,28 +133,28 @@ impl<'a> Generics<'a> { 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> { for constraint in ¶m.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) { @@ -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() + ), + ); } } @@ -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); diff --git a/nls/src/analyzer/interface.rs b/nls/src/analyzer/interface.rs new file mode 100644 index 00000000..c908e5e7 --- /dev/null +++ b/nls/src/analyzer/interface.rs @@ -0,0 +1,272 @@ +use std::collections::HashMap; + +use super::{ + common::{AnalyzerError, AstFnDef, AstNode, ReductionStatus, SelfKind, Type, TypeFn, TypeKind, TypedefStmt}, + symbol::SymbolTable, + typesys::Typesys, +}; +use crate::{project::Module, utils::format_impl_ident}; + +fn push_error(errors: &mut Vec, start: usize, end: usize, message: String) { + errors.push(AnalyzerError { start, end, message }); +} + +fn interface_equal(typesys: &mut Typesys, left: &Type, right: &Type) -> bool { + if left.ident.is_empty() || right.ident.is_empty() { + return false; + } + + if left.ident != right.ident { + return false; + } + + if left.args.len() != right.args.len() { + return false; + } + + for (left_arg, right_arg) in left.args.iter().zip(right.args.iter()) { + let Ok(reduced_left_arg) = typesys.reduction_type(left_arg.clone()) else { + return false; + }; + let Ok(reduced_right_arg) = typesys.reduction_type(right_arg.clone()) else { + return false; + }; + + if !typesys.type_compare(&reduced_left_arg, &reduced_right_arg) { + return false; + } + } + + true +} + +pub(crate) fn check_impl_interface_contains(typesys: &mut Typesys, typedef_stmt: &TypedefStmt, find_target_interface: &Type) -> bool { + if typedef_stmt.impl_interfaces.is_empty() { + return false; + } + + for impl_interface in &typedef_stmt.impl_interfaces { + if interface_equal(typesys, impl_interface, find_target_interface) { + return true; + } + + let Some(impl_typedef) = typesys.find_global_typedef(&impl_interface.ident) else { + continue; + }; + + if check_impl_interface_contains(typesys, &impl_typedef, find_target_interface) { + return true; + } + } + + false +} + +fn combination_interface(typesys: &mut Typesys, typedef_stmt: &mut TypedefStmt) -> Result<(), AnalyzerError> { + let TypeKind::Interface(origin_elements) = &mut typedef_stmt.type_expr.kind else { + return Err(AnalyzerError { + start: typedef_stmt.symbol_start, + end: typedef_stmt.symbol_end, + message: "typedef type is not interface".to_string(), + }); + }; + + let mut exists = HashMap::new(); + for element in origin_elements.clone() { + if let TypeKind::Fn(type_fn) = &element.kind { + exists.insert(type_fn.name.clone(), element); + } + } + + for impl_interface in &mut typedef_stmt.impl_interfaces { + *impl_interface = typesys.reduction_type(impl_interface.clone())?; + + if !matches!(impl_interface.kind, TypeKind::Interface(..)) { + return Err(AnalyzerError { + start: impl_interface.start, + end: impl_interface.end, + message: format!("interface '{}' impl target '{}' is not interface", typedef_stmt.ident, impl_interface.ident), + }); + } + + let TypeKind::Interface(elements) = &impl_interface.kind else { + unreachable!(); + }; + + for element in elements { + let TypeKind::Fn(type_fn) = &element.kind else { + return Err(AnalyzerError { + start: element.start, + end: element.end, + message: format!("interface '{}' contains non-fn method", typedef_stmt.ident), + }); + }; + + if let Some(exist_type) = exists.get(&type_fn.name) { + if !typesys.type_compare(element, exist_type) { + return Err(AnalyzerError { + start: element.start, + end: element.end, + message: format!("duplicate method '{}'", type_fn.name), + }); + } + continue; + } + + exists.insert(type_fn.name.clone(), element.clone()); + origin_elements.push(element.clone()); + } + } + + Ok(()) +} + +fn interface_extract_fn_type(typesys: &mut Typesys, fndef: &AstFnDef) -> Result { + if fndef.impl_type.kind.is_unknown() { + return Err(AnalyzerError { + start: fndef.symbol_start, + end: fndef.symbol_end, + message: "cannot infer function without interface".to_string(), + }); + } + + let mut type_fn = TypeFn { + name: fndef.fn_name.clone(), + tpl: fndef.is_tpl, + errable: fndef.is_errable, + rest: fndef.rest_param, + fx: fndef.is_fx, + param_types: Vec::new(), + return_type: typesys.reduction_type(fndef.return_type.clone())?, + }; + + for (i, param) in fndef.params.iter().enumerate() { + if !fndef.is_static && fndef.self_kind != SelfKind::Null && i == 0 { + continue; + } + + let param_type = { + let temp_param = param.lock().unwrap(); + temp_param.type_.clone() + }; + + let param_type = typesys.reduction_type(param_type)?; + type_fn.param_types.push(param_type); + } + + let mut result = Type::new(TypeKind::Fn(Box::new(type_fn))); + result.status = ReductionStatus::Done; + Ok(result) +} + +fn check_typedef_impl(typesys: &mut Typesys, impl_interface: &Type, typedef_ident: &str, typedef_stmt: &TypedefStmt) -> Result<(), String> { + let TypeKind::Interface(elements) = &impl_interface.kind else { + return Ok(()); + }; + + for expect_type in elements { + if expect_type.status != ReductionStatus::Done { + return Err(format!("type '{}' not done", expect_type.ident)); + } + + let TypeKind::Fn(interface_fn_type) = &expect_type.kind else { + return Err("interface element must be function type".to_string()); + }; + + let fn_ident = format_impl_ident(typedef_ident.to_string(), interface_fn_type.name.clone()); + let Some(ast_fndef_mutex) = typedef_stmt.method_table.get(&fn_ident) else { + return Err(format!( + "type '{}' not impl fn '{}' for interface '{}'", + typedef_ident, interface_fn_type.name, impl_interface.ident + )); + }; + + let ast_fndef = ast_fndef_mutex.lock().unwrap().clone(); + let actual_type = interface_extract_fn_type(typesys, &ast_fndef).map_err(|e| e.message)?; + + if !typesys.type_compare(expect_type, &actual_type) { + return Err(format!( + "the fn '{}' of type '{}' mismatch interface '{}'", + interface_fn_type.name, typedef_ident, impl_interface.ident + )); + } + } + + Ok(()) +} + +pub struct Interface<'a> { + module: &'a mut Module, + symbol_table: &'a mut SymbolTable, +} + +impl<'a> Interface<'a> { + pub fn new(module: &'a mut Module, symbol_table: &'a mut SymbolTable) -> Self { + Self { module, symbol_table } + } + + pub fn analyze(&mut self) -> Vec { + let mut errors = Vec::new(); + let stmts = self.module.stmts.clone(); + let mut typesys = Typesys::new(self.symbol_table, self.module); + + for stmt in stmts { + let AstNode::Typedef(typedef_mutex) = &stmt.node else { + continue; + }; + + let mut typedef = { + let typedef_stmt = typedef_mutex.lock().unwrap(); + if typedef_stmt.impl_interfaces.is_empty() { + continue; + } + typedef_stmt.clone() + }; + + if typedef.is_interface { + match typesys.reduction_type(typedef.type_expr.clone()) { + Ok(reduced) => typedef.type_expr = reduced, + Err(e) => { + push_error(&mut errors, e.start, e.end, e.message); + continue; + } + } + + if let Err(e) = combination_interface(&mut typesys, &mut typedef) { + push_error(&mut errors, e.start, e.end, e.message); + } + + let mut target = typedef_mutex.lock().unwrap(); + target.type_expr = typedef.type_expr.clone(); + target.impl_interfaces = typedef.impl_interfaces.clone(); + continue; + } + + for impl_interface in &mut typedef.impl_interfaces { + match typesys.reduction_type(impl_interface.clone()) { + Ok(reduced) => *impl_interface = reduced, + Err(e) => { + push_error(&mut errors, e.start, e.end, e.message); + impl_interface.err = true; + } + } + } + + let typedef_ident = typedef.ident.clone(); + for impl_interface in typedef.impl_interfaces.clone() { + if impl_interface.err { + continue; + } + + if let Err(message) = check_typedef_impl(&mut typesys, &impl_interface, &typedef_ident, &typedef) { + push_error(&mut errors, impl_interface.start, impl_interface.end, message); + } + } + + let mut target = typedef_mutex.lock().unwrap(); + target.impl_interfaces = typedef.impl_interfaces.clone(); + } + + errors + } +} diff --git a/nls/src/analyzer/lexer.rs b/nls/src/analyzer/lexer.rs index e9a5c834..ca0d9799 100644 --- a/nls/src/analyzer/lexer.rs +++ b/nls/src/analyzer/lexer.rs @@ -292,11 +292,15 @@ pub enum TokenType { As, #[strum(serialize = "fn")] Fn, + #[strum(serialize = "fx")] + Fx, #[strum(serialize = "import")] Import, #[strum(serialize = "return")] Return, + #[strum(serialize = "defer")] + Defer, #[strum(serialize = "interface")] Interface, @@ -412,11 +416,13 @@ impl Token { | TokenType::Break | TokenType::Continue | TokenType::Return + | TokenType::Defer | TokenType::Let | TokenType::Var | TokenType::Const | TokenType::Test | TokenType::Fn + | TokenType::Fx | TokenType::Import | TokenType::True | TokenType::False @@ -556,6 +562,7 @@ impl Lexer { "false" => TokenType::False, "float" => TokenType::Float, "fn" => TokenType::Fn, + "fx" => TokenType::Fx, "for" => TokenType::For, "go" => TokenType::Go, "if" => TokenType::If, @@ -570,6 +577,7 @@ impl Lexer { // "new" => TokenType::New, // new 可用于关键字 "null" => TokenType::Null, "return" => TokenType::Return, + "defer" => TokenType::Defer, // "set" => TokenType::Set, "string" => TokenType::String, "struct" => TokenType::Struct, diff --git a/nls/src/analyzer/semantic.rs b/nls/src/analyzer/semantic.rs index 77b787a9..e925ef73 100644 --- a/nls/src/analyzer/semantic.rs +++ b/nls/src/analyzer/semantic.rs @@ -16,6 +16,7 @@ pub struct Semantic<'a> { imports: Vec, current_local_fn_list: Vec>>, current_scope_id: NodeId, + in_defer_block_depth: usize, } impl<'a> Semantic<'a> { @@ -28,6 +29,7 @@ impl<'a> Semantic<'a> { current_scope_id: m.scope_id, // m.scope_id 是 global scope id module: m, current_local_fn_list: Vec::new(), + in_defer_block_depth: 0, } } @@ -1849,6 +1851,23 @@ impl<'a> Semantic<'a> { } } pub fn analyze_stmt(&mut self, stmt: &mut Box) { + if self.in_defer_block_depth > 0 { + if matches!( + &stmt.node, + AstNode::Return(_) | AstNode::Break | AstNode::Continue | AstNode::Throw(_) | AstNode::Ret(_) + ) { + errors_push( + self.module, + AnalyzerError { + start: stmt.start, + end: stmt.end, + message: "return/break/continue/throw/ret are not allowed inside defer block".to_string(), + }, + ); + return; + } + } + match &mut stmt.node { AstNode::Fake(expr) | AstNode::Ret(expr) => { self.analyze_expr(expr); @@ -1954,6 +1973,13 @@ impl<'a> Semantic<'a> { self.analyze_expr(expr); } } + AstNode::Defer(body) => { + self.in_defer_block_depth += 1; + self.enter_scope(ScopeKind::Local, stmt.start, stmt.end); + self.analyze_body(body); + self.exit_scope(); + self.in_defer_block_depth -= 1; + } AstNode::Typedef(type_alias_mutex) => { let mut typedef = type_alias_mutex.lock().unwrap(); // local type alias 不允许携带 param diff --git a/nls/src/analyzer/syntax.rs b/nls/src/analyzer/syntax.rs index 0070649c..08aff485 100644 --- a/nls/src/analyzer/syntax.rs +++ b/nls/src/analyzer/syntax.rs @@ -571,7 +571,7 @@ impl<'a> Syntax { )); } - while !self.is(TokenType::StmtEof) && !self.is(TokenType::Eof) && !self.is(TokenType::Fn) { + while !self.is(TokenType::StmtEof) && !self.is(TokenType::Eof) && !self.is(TokenType::Fn) && !self.is(TokenType::Fx) { let ident = self.must(TokenType::Ident)?.clone(); let mut param = GenericsParam::new(ident.literal.clone()); self.must(TokenType::Colon)?; @@ -611,7 +611,7 @@ impl<'a> Syntax { } // #where 支持最后一个约束后保留逗号 - if self.is(TokenType::StmtEof) || self.is(TokenType::Eof) || self.is(TokenType::Fn) { + if self.is(TokenType::StmtEof) || self.is(TokenType::Eof) || self.is(TokenType::Fn) || self.is(TokenType::Fx) { break; } } @@ -784,7 +784,11 @@ impl<'a> Syntax { _ if brace_level == current_brace_level => { // brace_level = 0 时只识别全局级别的语句 if brace_level == 0 { - if matches!(token, TokenType::Fn | TokenType::Var | TokenType::Import | TokenType::Type | TokenType::Const) || self.is_basic_type() { + if matches!( + token, + TokenType::Fn | TokenType::Fx | TokenType::Var | TokenType::Import | TokenType::Type | TokenType::Const + ) || self.is_basic_type() + { return true; } } else { @@ -793,6 +797,7 @@ impl<'a> Syntax { token, TokenType::Var | TokenType::Return + | TokenType::Defer | TokenType::If | TokenType::For | TokenType::Match @@ -830,7 +835,7 @@ impl<'a> Syntax { } } - fn parser_type_fn(&mut self) -> Result { + fn parser_type_fn(&mut self, is_fx: bool) -> Result { let mut param_types = Vec::new(); self.must(TokenType::LeftParen)?; @@ -891,9 +896,10 @@ impl<'a> Syntax { name: "".to_string(), param_types, return_type, - rest: false, + rest: is_rest, tpl: false, errable: is_errable, + fx: is_fx, }))) } @@ -1104,9 +1110,13 @@ impl<'a> Syntax { return Ok(t); } - // fn(Type, Type, ...):T! - if self.consume(TokenType::Fn) { - let type_fn_kind = self.parser_type_fn()?; + // fn(Type, Type, ...):T! / fx(Type, Type, ...):T! + if self.is(TokenType::Fn) || self.is(TokenType::Fx) { + let is_fx = self.consume(TokenType::Fx); + if !is_fx { + self.must(TokenType::Fn)?; + } + let type_fn_kind = self.parser_type_fn(is_fx)?; t.kind = type_fn_kind; t.end = self.prev().unwrap().end; return Ok(t); @@ -1300,13 +1310,34 @@ impl<'a> Syntax { self.must(TokenType::LeftCurly)?; while !self.consume(TokenType::RightCurly) { - let fn_start = self.must(TokenType::Fn)?.clone(); + if !self.is(TokenType::Fn) && !self.is(TokenType::Fx) { + return Err(SyntaxError(self.peek().start, self.peek().end, "interface only supports fn and fx".to_string())); + } + + let is_fx = self.consume(TokenType::Fx); + if !is_fx { + self.must(TokenType::Fn)?; + } + let fn_start = self.prev().unwrap().clone(); let fn_name_token = self.must(TokenType::Ident)?.clone(); let fn_name = fn_name_token.literal.clone(); - let mut type_fn_kind = self.parser_type_fn()?; + + let origin_type_params_table = self.type_params_table.clone(); + let mut method_generics_params = Vec::new(); + if self.consume(TokenType::LeftAngle) { + self.type_params_table = origin_type_params_table.clone(); + self.parser_parse_generics_decl(&mut method_generics_params)?; + self.must(TokenType::RightAngle)?; + } + + let mut type_fn_kind = self.parser_type_fn(is_fx)?; if let TypeKind::Fn(fn_kind) = &mut type_fn_kind { fn_kind.name = fn_name.clone(); + if !method_generics_params.is_empty() { + fn_kind.tpl = true; + } } + self.type_params_table = origin_type_params_table; if exists.contains_key(&fn_name) { errors_push( @@ -1722,6 +1753,7 @@ impl<'a> Syntax { generics_args, args: Vec::new(), spread: false, + inject_self_arg: false, }; call.args = self.parser_call_args(&mut call)?; @@ -2155,6 +2187,7 @@ impl<'a> Syntax { args: Vec::new(), generics_args: Vec::new(), spread: false, + inject_self_arg: false, }; call.args = self.parser_call_args(&mut call)?; @@ -2290,7 +2323,7 @@ impl<'a> Syntax { } // fndef type (stmt 维度禁止了匿名 fndef, 所以这里一定是 fndef type) - if self.is(TokenType::Fn) && self.next_is(1, TokenType::LeftParen) { + if (self.is(TokenType::Fn) || self.is(TokenType::Fx)) && self.next_is(1, TokenType::LeftParen) { return true; } @@ -2328,6 +2361,57 @@ impl<'a> Syntax { result } + fn parser_for_range_rewrite(&self, first: VarDeclExpr, range_start: Box, range_end: Box, body: AstBody) -> Box { + let first_ident = first.ident.clone(); + let start = range_start.start; + let end = body.end; + + let init = Box::new(Stmt { + start: range_start.start, + end: range_start.end, + node: AstNode::VarDef(Arc::new(Mutex::new(first)), range_start), + }); + + let cond = Box::new(Expr { + start, + end: range_end.end, + type_: Type::default(), + target_type: Type::default(), + node: AstNode::Binary(ExprOp::Lt, Box::new(Expr::ident(start, start, first_ident.clone(), 0)), range_end), + }); + + let update = Box::new(Stmt { + start, + end: start, + node: AstNode::Assign( + Box::new(Expr::ident(start, start, first_ident.clone(), 0)), + Box::new(Expr { + start, + end: start, + type_: Type::default(), + target_type: Type::default(), + node: AstNode::Binary( + ExprOp::Add, + Box::new(Expr::ident(start, start, first_ident, 0)), + Box::new(Expr { + start, + end: start, + type_: Type::default(), + target_type: Type::default(), + node: AstNode::Literal(TypeKind::Int, "1".to_string()), + }), + ), + }), + ), + }); + + Box::new(Stmt { + start, + end, + node: AstNode::ForTradition(init, cond, update, body), + }) + } + fn parser_for_stmt(&mut self) -> Result, SyntaxError> { self.must(TokenType::For)?; @@ -2353,6 +2437,7 @@ impl<'a> Syntax { } // for k,v in map {} + // for i in start..end {} if self.is(TokenType::Ident) && (self.next_is(1, TokenType::Comma) || self.next_is(1, TokenType::In)) { let first_ident = self.must(TokenType::Ident)?; let first = VarDeclExpr { @@ -2383,10 +2468,23 @@ impl<'a> Syntax { }; self.must(TokenType::In)?; - let iterate = self.parser_precedence_expr(SyntaxPrecedence::TypeCast, TokenType::Unknown)?; + let in_expr = self.parser_precedence_expr(SyntaxPrecedence::TypeCast, TokenType::Range)?; + if self.consume(TokenType::Range) { + if second.is_some() { + return Err(SyntaxError( + self.peek().start, + self.peek().end, + "for range only supports one iterator variable".to_string(), + )); + } + let range_end = self.parser_precedence_expr(SyntaxPrecedence::TypeCast, TokenType::Unknown)?; + let body = self.parser_body(false)?; + return Ok(self.parser_for_range_rewrite(first, in_expr, range_end, body)); + } + let body = self.parser_body(false)?; - stmt.node = AstNode::ForIterator(iterate, Arc::new(Mutex::new(first)), second, body); + stmt.node = AstNode::ForIterator(in_expr, Arc::new(Mutex::new(first)), second, body); return Ok(stmt); } @@ -2495,6 +2593,32 @@ impl<'a> Syntax { Ok(stmt) } + fn parser_defer_stmt(&mut self) -> Result, SyntaxError> { + let mut stmt = self.stmt_new(); + self.must(TokenType::Defer)?; + + let body = if self.is(TokenType::LeftCurly) { + self.parser_body(false)? + } else { + if self.is_stmt_eof() || self.is(TokenType::RightCurly) { + return Err(SyntaxError(self.peek().start, self.peek().end, "defer must have statement body".to_string())); + } + + let defer_stmt = self.parser_local_stmt_core(false)?; + let start = defer_stmt.start; + let end = defer_stmt.end; + AstBody { + stmts: vec![defer_stmt], + start, + end, + } + }; + + stmt.end = body.end; + stmt.node = AstNode::Defer(body); + Ok(stmt) + } + fn parser_import_stmt(&mut self) -> Result, SyntaxError> { let mut stmt = self.stmt_new(); self.must(TokenType::Import)?; @@ -2760,9 +2884,13 @@ impl<'a> Syntax { let start = self.peek().start; let end = self.peek().end; - self.must(TokenType::Fn)?; + let is_fx = self.consume(TokenType::Fx); + if !is_fx { + self.must(TokenType::Fn)?; + } let mut fndef = AstFnDef::default(); + fndef.is_fx = is_fx; fndef.symbol_start = start; fndef.symbol_end = end; @@ -2802,6 +2930,7 @@ impl<'a> Syntax { args: Vec::new(), generics_args: Vec::new(), spread: false, + inject_self_arg: false, }; call.args = self.parser_call_args(&mut call)?; @@ -3167,7 +3296,11 @@ impl<'a> Syntax { fn parser_fndef_stmt(&mut self, mut fndef: AstFnDef) -> Result, SyntaxError> { let mut stmt = self.stmt_new(); fndef.symbol_start = self.peek().start; - self.must(TokenType::Fn)?; + if self.consume(TokenType::Fx) { + fndef.is_fx = true; + } else { + self.must(TokenType::Fn)?; + } // 检查是否是类型实现函数 if self.is_impl_fn() { @@ -3372,13 +3505,21 @@ impl<'a> Syntax { } } - if fndef.pending_where_params.is_some() && !self.is(TokenType::Fn) { - return Err(SyntaxError(self.peek().start, self.peek().end, "#where can only be applied to fn".to_string())); + if fndef.pending_where_params.is_some() && !self.is(TokenType::Fn) && !self.is(TokenType::Fx) { + return Err(SyntaxError( + self.peek().start, + self.peek().end, + "#where can only be applied to fn/fx".to_string(), + )); } if self.is(TokenType::Type) { if fndef.pending_where_params.is_some() { - return Err(SyntaxError(self.peek().start, self.peek().end, "#where can only be applied to fn".to_string())); + return Err(SyntaxError( + self.peek().start, + self.peek().end, + "#where can only be applied to fn/fx".to_string(), + )); } let result = self.parser_typedef_stmt()?; if is_private { @@ -3387,7 +3528,7 @@ impl<'a> Syntax { } } Ok(result) - } else if self.is(TokenType::Fn) { + } else if self.is(TokenType::Fn) || self.is(TokenType::Fx) { self.parser_fndef_stmt(fndef) } else if self.is(TokenType::Const) { let result = self.parser_constdef_stmt()?; @@ -3417,7 +3558,7 @@ impl<'a> Syntax { Err(SyntaxError( self.peek().start, self.peek().end, - format!("the label can only be applied to type, fn, const, or var"), + format!("the label can only be applied to type, fn, fx, const, or var"), )) } } @@ -3487,7 +3628,7 @@ impl<'a> Syntax { self.parser_label()? } else if self.is(TokenType::Test) { self.parser_test_stmt()? - } else if self.is(TokenType::Fn) { + } else if self.is(TokenType::Fn) || self.is(TokenType::Fx) { self.parser_fndef_stmt(AstFnDef::default())? } else if self.is(TokenType::Import) { self.parser_import_stmt()? @@ -3536,7 +3677,7 @@ impl<'a> Syntax { Ok(stmt) } - fn parser_local_stmt(&mut self) -> Result, SyntaxError> { + fn parser_local_stmt_core(&mut self, consume_stmt_end: bool) -> Result, SyntaxError> { let stmt = if self.is(TokenType::Var) { self.parser_var_begin_stmt()? } else if self.is_type_begin_stmt() { @@ -3561,6 +3702,8 @@ impl<'a> Syntax { self.parser_for_stmt()? } else if self.is(TokenType::Return) { self.parser_return_stmt()? + } else if self.is(TokenType::Defer) { + self.parser_defer_stmt()? } else if self.is(TokenType::Import) { self.parser_import_stmt()? } else if self.is(TokenType::Type) { @@ -3588,11 +3731,17 @@ impl<'a> Syntax { self.parser_expr_begin_stmt()? }; - self.must_stmt_end()?; + if consume_stmt_end { + self.must_stmt_end()?; + } Ok(stmt) } + fn parser_local_stmt(&mut self) -> Result, SyntaxError> { + self.parser_local_stmt_core(true) + } + fn parser_precedence_expr(&mut self, precedence: SyntaxPrecedence, exclude: TokenType) -> Result, SyntaxError> { // 读取表达式前缀 let rule = self.find_rule(self.peek().token_type.clone()); @@ -3790,6 +3939,7 @@ impl<'a> Syntax { })], generics_args: Vec::new(), spread: false, + inject_self_arg: false, }; call_stmt.node = AstNode::Call(call); let end = self.prev().unwrap().end; @@ -4144,7 +4294,7 @@ impl<'a> Syntax { self.parser_go_expr() } else if self.is(TokenType::Match) { self.parser_match_expr() - } else if self.is(TokenType::Fn) { + } else if self.is(TokenType::Fn) || self.is(TokenType::Fx) { self.parser_fndef_expr() } else if self.parser_is_new() { self.parser_new_expr() diff --git a/nls/src/analyzer/typesys.rs b/nls/src/analyzer/typesys.rs index 143ce7ef..d26f7f05 100644 --- a/nls/src/analyzer/typesys.rs +++ b/nls/src/analyzer/typesys.rs @@ -9,6 +9,7 @@ use std::hash::{Hash, Hasher}; use super::{ common::{AnalyzerError, AstCall, AstNode, Expr, Stmt, Type, TypeFn, TypedefStmt, VarDeclExpr}, + interface, symbol::{NodeId, SymbolTable}, }; use crate::{ @@ -254,6 +255,7 @@ impl GenericSpecialFnClone { AstNode::FnDef(fn_def_mutex) => AstNode::FnDef(self.deep_clone(fn_def_mutex)), AstNode::Throw(expr) => AstNode::Throw(Box::new(self.clone_expr(expr))), AstNode::Return(expr_opt) => AstNode::Return(expr_opt.as_ref().map(|e| Box::new(self.clone_expr(e)))), + AstNode::Defer(body) => AstNode::Defer(self.clone_body(body)), AstNode::Call(call) => AstNode::Call(self.clone_call(call)), AstNode::Continue => AstNode::Continue, AstNode::Break => AstNode::Break, @@ -319,6 +321,7 @@ impl GenericSpecialFnClone { generics_args: call.generics_args.clone(), args: call.args.iter().map(|e| Box::new(self.clone_expr(e))).collect(), spread: call.spread, + inject_self_arg: call.inject_self_arg, } } } @@ -422,6 +425,8 @@ impl<'a> Typesys<'a> { result.status = ReductionStatus::Done; result.kind = Type::cross_kind_trans(&result.kind); + result.storage_kind = Type::storage_kind(&result.kind); + result.in_heap = Type::kind_in_heap(&result.kind); // recycle_check let mut visited = HashSet::new(); @@ -446,62 +451,13 @@ impl<'a> Typesys<'a> { } } - fn combination_interface(&mut self, typedef_stmt: &mut TypedefStmt, visited: &mut HashMap) -> Result<(), AnalyzerError> { - // 确保类型表达式已完成归约且是接口类型 - debug_assert!(typedef_stmt.type_expr.status == ReductionStatus::Done); - - // 获取原始接口中的方法列表 - let TypeKind::Interface(origin_elements) = &mut typedef_stmt.type_expr.kind else { - return Err(AnalyzerError { - start: typedef_stmt.symbol_start, - end: typedef_stmt.symbol_end, - message: "typedef type is not interface".to_string(), - }); + pub(crate) fn find_global_typedef(&self, ident: &str) -> Option { + let symbol = self.symbol_table.find_global_symbol(ident)?; + let SymbolKind::Type(typedef_mutex) = symbol.kind.clone() else { + return None; }; - - // 创建一个 HashMap 用于跟踪已存在的方法 - let mut exists = HashMap::new(); - - // 将原始接口中的方法添加到 exists 中 - for element in origin_elements.clone() { - if let TypeKind::Fn(type_fn) = &element.kind { - exists.insert(type_fn.name.clone(), element.clone()); - } - } - - // 合并实现的接口 - for impl_interface in &mut typedef_stmt.impl_interfaces { - // 归约接口类型 - *impl_interface = match self.reduction_type_visited(impl_interface.clone(), visited) { - Ok(r) => r, - Err(_) => continue, - }; - - if let TypeKind::Interface(elements) = &impl_interface.kind { - for element in elements { - if let TypeKind::Fn(type_fn) = &element.kind { - // 检查方法是否已存在 - if let Some(exist_type) = exists.get(&type_fn.name) { - // 比较方法签名是否一致 - if !self.type_compare(&element, exist_type) { - return Err(AnalyzerError { - start: element.start, - end: element.end, - message: format!("duplicate method '{}'", type_fn.name), - }); - } - continue; - } - - // 添加新方法 - exists.insert(type_fn.name.clone(), element.clone()); - origin_elements.push(element.clone()); - } - } - } - } - - Ok(()) + let typedef = typedef_mutex.lock().unwrap().clone(); + Some(typedef) } fn reduction_type_ident(&mut self, mut t: Type, visited: &mut HashMap) -> Result { @@ -629,23 +585,6 @@ impl<'a> Typesys<'a> { self.generics_args_stack.push(args_table); let reduction_result: Result = (|| { - if !generic_typedef.impl_interfaces.is_empty() { - if generic_typedef.is_interface { - debug_assert!(generic_typedef.type_expr.status == ReductionStatus::Done); - debug_assert!(matches!(generic_typedef.type_expr.kind, TypeKind::Interface(..))); - self.combination_interface(&mut generic_typedef, visited)?; - } else { - for impl_interface in &mut generic_typedef.impl_interfaces { - *impl_interface = self.reduction_type_visited(impl_interface.clone(), visited)?; - } - - for impl_interface in &generic_typedef.impl_interfaces { - self.check_typedef_impl(impl_interface, t.ident.clone(), &generic_typedef) - .map_err(|e| AnalyzerError { start, end, message: e })?; - } - } - } - let right_type = self.reduction_type_visited(generic_typedef.type_expr.clone(), visited)?; Ok(right_type) })(); @@ -661,11 +600,6 @@ impl<'a> Typesys<'a> { } }; - { - let mut typedef = typedef_mutex.lock().unwrap(); - typedef.impl_interfaces = generic_typedef.impl_interfaces.clone(); - } - t.args = impl_args; t.kind = right_type.kind; t.status = right_type.status; @@ -703,40 +637,6 @@ impl<'a> Typesys<'a> { let mut typedef = typedef_mutex.lock().unwrap(); typedef.type_expr = type_expr; - if !typedef.impl_interfaces.is_empty() { - if typedef.is_interface { - debug_assert!(typedef.type_expr.status == ReductionStatus::Done); - debug_assert!(matches!(typedef.type_expr.kind, TypeKind::Interface(..))); - if let Err(e) = self.combination_interface(&mut typedef, visited) { - if reduction_ident_depth_entered { - Self::reduction_ident_depth_leave(visited, &t.ident); - } - return Err(e); - } - } else { - for impl_interface in &mut typedef.impl_interfaces { - *impl_interface = match self.reduction_type_visited(impl_interface.clone(), visited) { - Ok(impl_interface) => impl_interface, - Err(e) => { - if reduction_ident_depth_entered { - Self::reduction_ident_depth_leave(visited, &t.ident); - } - return Err(e); - } - }; - } - - for impl_interface in &typedef.impl_interfaces { - if let Err(e) = self.check_typedef_impl(impl_interface, t.ident.clone(), &typedef) { - if reduction_ident_depth_entered { - Self::reduction_ident_depth_leave(visited, &t.ident); - } - return Err(AnalyzerError { start, end, message: e }); - } - } - } - } - t.kind = typedef.type_expr.kind.clone(); t.status = typedef.type_expr.status; @@ -894,8 +794,14 @@ impl<'a> Typesys<'a> { debug_assert!(t.kind == TypeKind::Ident); debug_assert!(t.ident_kind == TypeIdentKind::GenericsParam); - let arg_type = arg_table.get(&t.ident).unwrap(); - return self.reduction_type_visited(arg_type.clone(), visited).unwrap(); + let Some(arg_type) = arg_table.get(&t.ident) else { + return t; + }; + + match self.reduction_type_visited(arg_type.clone(), visited) { + Ok(specialized) => specialized, + Err(_) => t, + } } pub fn reduction_type(&mut self, t: Type) -> Result { @@ -1178,7 +1084,7 @@ impl<'a> Typesys<'a> { if let SymbolKind::Type(typedef_mutex) = symbol.kind.clone() { let typedef = typedef_mutex.lock().unwrap(); - let found = self.check_impl_interface_contains(&typedef, &src_type); + let found = interface::check_impl_interface_contains(self, &typedef, &src_type); // 禁止制鸭子类型 if !found { @@ -1188,13 +1094,6 @@ impl<'a> Typesys<'a> { message: format!("type '{}' not impl '{}' interface", temp_target_type.ident, src_type), }); } - - self.check_typedef_impl(&src_type, temp_target_type.ident.clone(), &typedef) - .map_err(|e| AnalyzerError { - start: as_expr.start, - end: as_expr.end, - message: e, - })?; } else { unreachable!(); } @@ -2533,6 +2432,7 @@ impl<'a> Typesys<'a> { args: vec![first_arg, async_expr.flag_expr.clone().unwrap()], generics_args: vec![async_expr.return_type.clone()], spread: false, + inject_self_arg: false, }; expr.node = AstNode::Call(call); @@ -2620,12 +2520,12 @@ impl<'a> Typesys<'a> { if let TypeKind::Struct(_, _, type_properties) = &mut type_.kind { *properties = self.infer_struct_properties(type_properties, properties, expr.start, expr.end)?; } else { - // check scala type or arr - if !Type::is_scala_type(&type_.kind) && !matches!(type_.kind, TypeKind::Arr(..)) { + // only scalar type can use new + if Type::storage_kind(&type_.kind) == StorageKind::Ptr { return Err(AnalyzerError { start: expr.start, end: expr.end, - message: "'new' operator can only be used with scalar types (number/boolean/struct/array)".to_string(), + message: "'new' operator can only be used with scalar types".to_string(), }); } @@ -2733,6 +2633,23 @@ impl<'a> Typesys<'a> { debug_assert!(expr.type_.status == ReductionStatus::Done); debug_assert!(interface_type.status == ReductionStatus::Done); + if let TypeKind::Interface(elements) = &interface_type.kind { + for element in elements { + if let TypeKind::Fn(type_fn) = &element.kind { + if type_fn.tpl { + return Err(AnalyzerError { + start: expr.start, + end: expr.end, + message: format!( + "interface '{}' contains generic method '{}', cannot be used as dynamic dispatch.", + interface_type.ident, type_fn.name + ), + }); + } + } + } + } + // 自动解引用指针类型 let src_type = match &expr.type_.kind { TypeKind::Ref(value_type) | TypeKind::Ptr(value_type) => *value_type.clone(), @@ -2764,7 +2681,7 @@ impl<'a> Typesys<'a> { let typedef_stmt = typedef_stmt_mutex.lock().unwrap(); // 检查类型是否实现了目标接口 - let found = self.check_impl_interface_contains(&typedef_stmt, &interface_type); + let found = interface::check_impl_interface_contains(self, &typedef_stmt, &interface_type); // 禁止鸭子类型 if !found { @@ -2775,14 +2692,6 @@ impl<'a> Typesys<'a> { }); } - // 检查接口实现的完整性 - self.check_typedef_impl(&interface_type, src_type.ident.clone(), &typedef_stmt) - .map_err(|e| AnalyzerError { - start: expr.start, - end: expr.end, - message: e, - })?; - // 创建类型转换表达式 Ok(Box::new(Expr { start: expr.start, @@ -2802,6 +2711,14 @@ impl<'a> Typesys<'a> { *kind = literal_type.kind.clone(); let mut target_kind = infer_target_type.kind.clone(); + + // keep compiler behavior: null can be assigned to anyptr, and literal rewritten to 0 + if matches!(literal_type.kind, TypeKind::Null) && matches!(target_kind, TypeKind::Anyptr) { + *kind = TypeKind::Anyptr; + *literal_value = "0".to_string(); + return Ok(infer_target_type); + } + if matches!(target_kind, TypeKind::Anyptr) { target_kind = TypeKind::Uint; } @@ -3248,11 +3165,11 @@ impl<'a> Typesys<'a> { fn generics_args_table( &mut self, - call_data: (Vec>, Vec, bool), + call_data: (Vec>, Vec, bool, bool), return_target_type: Type, temp_fndef_mutex: Arc>, ) -> Result, String> { - let (mut args, generics_args, spread) = call_data; + let (mut args, generics_args, spread, inject_self_arg) = call_data; let mut table = HashMap::new(); let mut temp_fndef = temp_fndef_mutex.lock().unwrap(); @@ -3280,7 +3197,7 @@ impl<'a> Typesys<'a> { let mut formal_param_offset = 0; // impl 方法调用在 generics 特化阶段尚未注入 self 参数 - if temp_fndef.is_impl && !temp_fndef.is_static && temp_fndef.self_kind != SelfKind::Null { + if temp_fndef.is_impl && !temp_fndef.is_static && temp_fndef.self_kind != SelfKind::Null && !inject_self_arg { formal_param_offset = 1; } @@ -3356,7 +3273,7 @@ impl<'a> Typesys<'a> { fn generics_special_fn( &mut self, - call_data: (Vec>, Vec, bool), + call_data: (Vec>, Vec, bool, bool), target_type: Type, temp_fndef_mutex: Arc>, module_scope_id: NodeId, @@ -3502,7 +3419,7 @@ impl<'a> Typesys<'a> { &mut self, target_type: Type, symbol_id: NodeId, - call_data: (Vec>, Vec, bool), + call_data: (Vec>, Vec, bool, bool), ) -> Result>>, String> { // cal target generics fn symbol_id let symbol = self.symbol_table.get_symbol(symbol_id).unwrap(); @@ -3618,7 +3535,7 @@ impl<'a> Typesys<'a> { }); } - if matches!(self_arg.type_.kind, TypeKind::Ref(_)) || self_arg.type_.is_heap_impl() { + if matches!(self_arg.type_.kind, TypeKind::Ref(_)) || Type::storage_kind(&self_arg.type_.kind) == StorageKind::Ptr { return Ok(()); } @@ -3696,7 +3613,7 @@ impl<'a> Typesys<'a> { // 由于存在函数重载,所以需要进行多次匹配找到最合适的 is_tpl 函数, 如果没有重载 temp_fndef 就是 tpl_fndef let special_fn = self .generics_special_fn( - (call.args.clone(), call.generics_args.clone(), call.spread.clone()), + (call.args.clone(), call.generics_args.clone(), call.spread, call.inject_self_arg), target_type, temp_fndef_mutex, module_scope_id, @@ -3909,6 +3826,7 @@ impl<'a> Typesys<'a> { let mut self_arg = select_left.clone(); // {'a':1}.del('a') -> map_del({'a':1}, 'a') self.self_arg_rewrite(&type_fn, &mut self_arg)?; new_args.push(self_arg); + call.inject_self_arg = true; } new_args.extend(call.args.iter().cloned()); call.args = new_args; @@ -4130,6 +4048,25 @@ impl<'a> Typesys<'a> { self.infer_call_args(call, *type_fn.clone()); call.return_type = type_fn.return_type.clone(); + { + let current_fn = self.current_fn_mutex.lock().unwrap(); + if current_fn.is_fx && !type_fn.fx { + return Err(AnalyzerError { + start, + end, + message: format!( + "calling fn `{}` from fx `{}` is not allowed.", + if type_fn.name.is_empty() { + "lambda".to_string() + } else { + type_fn.name.clone() + }, + current_fn.fn_name + ), + }); + } + } + if type_fn.errable && check_errable { // 当前 fn 必须允许 is_errable 或者当前位于 be_caught 中 let current_fn = self.current_fn_mutex.lock().unwrap(); @@ -4431,6 +4368,9 @@ impl<'a> Typesys<'a> { self.infer_right_expr(expr, Type::default())?; } } + AstNode::Defer(body) => { + self.infer_body(body); + } AstNode::Typedef(type_alias_mutex) => { self.rewrite_typedef(type_alias_mutex); } @@ -4531,9 +4471,6 @@ impl<'a> Typesys<'a> { return false; } - debug_assert!(!Type::ident_is_generics_param(&dst)); - debug_assert!(!Type::ident_is_generics_param(src)); - // 检查类型状态 if dst.status != ReductionStatus::Done { return false; @@ -4545,6 +4482,13 @@ impl<'a> Typesys<'a> { return false; } + if Type::ident_is_generics_param(&dst) { + if !Type::ident_is_generics_param(src) { + return false; + } + return dst.ident == src.ident; + } + if dst.ident_kind == TypeIdentKind::Builtin && dst.ident == "all_t".to_string() { return true; } @@ -4667,6 +4611,8 @@ impl<'a> Typesys<'a> { || left_fn.param_types.len() != right_fn.param_types.len() || left_fn.rest != right_fn.rest || left_fn.errable != right_fn.errable + || left_fn.fx != right_fn.fx + || left_fn.tpl != right_fn.tpl { return false; } @@ -4789,6 +4735,8 @@ impl<'a> Typesys<'a> { || left_fn.param_types.len() != right_fn.param_types.len() || left_fn.rest != right_fn.rest || left_fn.errable != right_fn.errable + || left_fn.fx != right_fn.fx + || left_fn.tpl != right_fn.tpl { return false; } @@ -4909,7 +4857,7 @@ impl<'a> Typesys<'a> { // 为什么要在这里进行 ptr of, 只有在 infer 之后才能确定 alias 的具体类型,从而进一步判断是否需要 ptrof // is_impl 并且是第一个参数时,根据 self_kind 处理 if fndef.is_impl && !fndef.is_static && fndef.self_kind != SelfKind::Null && i == 0 { - if param_type.is_stack_impl() { + if Type::storage_kind(¶m_type.kind) != StorageKind::Ptr { match fndef.self_kind { SelfKind::SelfRefT => { param_type = Type::ref_of(param_type); @@ -4922,10 +4870,23 @@ impl<'a> Typesys<'a> { } } } else { - // 堆分配类型(vec/map/set/chan等)有隐式指针接收器 - // 不需要转换,但必须是 SelfPtrT - if fndef.self_kind != SelfKind::SelfRefT && fndef.self_kind != SelfKind::Null { - // 可以在这里添加警告或错误,但暂时只是保持原样 + if Type::is_impl_builtin_type(¶m_type.kind) { + if fndef.self_kind != SelfKind::SelfT { + return Err(AnalyzerError { + start: fndef.symbol_start, + end: fndef.symbol_end, + message: format!( + "heap-allocated builtin type '{}' requires explicit `self` receiver; use `fn {}.method(self)`", + param_type, param_type + ), + }); + } + } else if fndef.self_kind != SelfKind::SelfRefT { + return Err(AnalyzerError { + start: fndef.symbol_start, + end: fndef.symbol_end, + message: format!("heap-allocated type '{}' requires `&self` receiver; use `fn T.method(&self)`", param_type), + }); } } } @@ -4945,6 +4906,7 @@ impl<'a> Typesys<'a> { tpl: fndef.is_tpl, errable: fndef.is_errable, rest: fndef.rest_param, + fx: fndef.is_fx, param_types, }))); @@ -5122,98 +5084,6 @@ impl<'a> Typesys<'a> { return true; } - /** - * 为了能够和 impl 中声明的 fn 进行 compare, 需要将 fn 将 self 参数暂时去除, 并且不改变 fndef 中的 ident/return_type/type 等 - */ - fn infer_impl_fn_decl(&mut self, fndef: &AstFnDef) -> Result { - if fndef.impl_type.kind.is_unknown() { - return Err(AnalyzerError { - start: 0, - end: 0, - message: "cannot infer function without interface".to_string(), - }); - } - - let mut type_fn = TypeFn { - name: fndef.fn_name.clone(), - tpl: fndef.is_tpl, - errable: fndef.is_errable, - rest: fndef.rest_param, - param_types: Vec::new(), - return_type: self.reduction_type(fndef.return_type.clone())?, - }; - - // 跳过 self(仅当存在 receiver) - for (i, param) in fndef.params.iter().enumerate() { - if !fndef.is_static && fndef.self_kind != SelfKind::Null && i == 0 { - continue; - } - let mut param_type = { - let temp_param = param.lock().unwrap(); - temp_param.type_.clone() - }; - - param_type = self.reduction_type(param_type)?; - - type_fn.param_types.push(param_type.clone()); - - { - let mut temp_param = param.lock().unwrap(); - temp_param.type_ = param_type.clone(); - } - } - - Ok(Type::new(TypeKind::Fn(Box::new(type_fn)))) - } - - fn check_typedef_impl(&mut self, impl_interface: &Type, typedef_ident: String, typedef_stmt: &TypedefStmt) -> Result<(), String> { - // 获取接口中定义的所有方法 - if let TypeKind::Interface(elements) = &impl_interface.kind { - // 检查接口中的每个方法是否被实现 - for expect_type in elements { - if expect_type.status != ReductionStatus::Done { - return Err(format!("type '{}' not done", expect_type.ident)); - } - - if let TypeKind::Fn(interface_fn_type) = &expect_type.kind { - // 构造实现方法的标识符 - let fn_ident = format_impl_ident(typedef_ident.clone(), interface_fn_type.name.clone()); - - // 从 typedef_stmt 的 method_table 中查找对应的方法实现 - let ast_fndef_option = typedef_stmt.method_table.get(&fn_ident); - - if ast_fndef_option.is_none() { - return Err(format!( - "type '{}' not impl fn '{}' for interface '{}'", - typedef_ident, interface_fn_type.name, impl_interface.ident - )); - } - - let ast_fndef = { - let temp = ast_fndef_option.unwrap().lock().unwrap(); - temp.clone() - }; - - // 获取实现方法的类型 - let actual_type = self.infer_impl_fn_decl(&ast_fndef).map_err(|e| e.message)?; - - // 比较接口方法类型和实现方法类型是否匹配 - // 注意:实现方法的第一个参数是 self,而接口方法没有 - if !self.type_compare(expect_type, &actual_type) { - return Err(format!( - "the fn '{}' of type '{}' mismatch interface '{}'", - interface_fn_type.name, typedef_ident, impl_interface.ident - )); - } - } else { - return Err(format!("interface element must be function type")); - } - } - } - - Ok(()) - } - fn interface_has_builtin_deny(&self, interface_type: &Type) -> bool { interface_type.ident == NONVOID_IDENT } @@ -5336,15 +5206,13 @@ impl<'a> Typesys<'a> { if let SymbolKind::Type(typedef_mutex) = symbol.kind.clone() { let typedef = typedef_mutex.lock().unwrap(); - let found = self.check_impl_interface_contains(&typedef, expect_interface_type); + let found = interface::check_impl_interface_contains(self, &typedef, expect_interface_type); if !found { return Err(format!( "type '{}' not impl '{}' interface", temp_target_type.ident, expect_interface_type.ident )); } - - self.check_typedef_impl(expect_interface_type, temp_target_type.ident.clone(), &typedef)?; } else { unreachable!(); } @@ -5353,33 +5221,6 @@ impl<'a> Typesys<'a> { Ok(()) } - fn check_impl_interface_contains(&mut self, typedef_stmt: &TypedefStmt, find_target_interface: &Type) -> bool { - if typedef_stmt.impl_interfaces.len() == 0 { - return false; - } - - for impl_interface in &typedef_stmt.impl_interfaces { - if impl_interface.ident == find_target_interface.ident { - return true; - } - - // find impl interface from symbol table - let symbol = match self.symbol_table.find_global_symbol(&impl_interface.ident) { - Some(s) => s, - None => continue, - }; - - if let SymbolKind::Type(def_type_mutex) = symbol.kind.clone() { - let t = def_type_mutex.lock().unwrap(); - if self.check_impl_interface_contains(&t, find_target_interface) { - return true; - } - } - } - - return false; - } - pub fn pre_infer(&mut self) -> Vec { // 遍历 module 下的所有的 fndef, 包含 global fn 和 local fn let global_fndefs = self.module.global_fndefs.clone(); diff --git a/nls/src/project.rs b/nls/src/project.rs index cf0aea29..dabf3f20 100644 --- a/nls/src/project.rs +++ b/nls/src/project.rs @@ -2,6 +2,7 @@ use crate::analyzer::common::{AnalyzerError, AstFnDef, AstNode, ImportStmt, Pack use crate::analyzer::flow::Flow; use crate::analyzer::generics::Generics; use crate::analyzer::global_eval::GlobalEval; +use crate::analyzer::interface::Interface; use crate::analyzer::lexer::{Lexer, Token}; use crate::analyzer::semantic::Semantic; use crate::analyzer::symbol::{NodeId, SymbolTable}; @@ -396,6 +397,16 @@ impl Project { Generics::new(m, &symbol_table).analyze(); } + // interface pass + // keep compiler order: after generics, validate typedef impl interfaces early + for index in module_indexes.clone() { + let mut module_db = self.module_db.lock().unwrap(); + let mut symbol_table = self.symbol_table.lock().unwrap(); + let m = &mut module_db[index]; + let errors = Interface::new(m, &mut symbol_table).analyze(); + m.analyzer_errors.extend(errors); + } + // all pre infer for index in module_indexes.clone() { let mut module_db = self.module_db.lock().unwrap(); diff --git a/nls/tests/sync_compiler_changes_test.rs b/nls/tests/sync_compiler_changes_test.rs new file mode 100644 index 00000000..2a93328d --- /dev/null +++ b/nls/tests/sync_compiler_changes_test.rs @@ -0,0 +1,131 @@ +use nls::analyzer::module_unique_ident; +use nls::project::Project; +use std::fs; +use std::path::PathBuf; +use std::time::{SystemTime, UNIX_EPOCH}; + +fn case_root(name: &str) -> PathBuf { + let nanos = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_nanos(); + let dir = std::env::temp_dir().join(format!("nls_sync_{}_{}", name, nanos)); + fs::create_dir_all(&dir).unwrap(); + dir +} + +async fn build_errors(name: &str, code: &str) -> Vec { + let root = case_root(name); + let file_path = root.join("main.n"); + fs::write(&file_path, code).unwrap(); + + let mut project = Project::new(root.to_string_lossy().to_string()).await; + let module_ident = module_unique_ident(&project.root, &file_path.to_string_lossy()); + let module_index = project.build(&file_path.to_string_lossy(), &module_ident, Some(code.to_string())).await; + + let module_db = project.module_db.lock().unwrap(); + module_db[module_index].analyzer_errors.iter().map(|e| e.message.clone()).collect() +} + +#[tokio::test] +async fn test_for_range_and_defer_should_pass() { + let code = r#" +fn main() { + for i in 0..5 { + defer println(i) + } +} +"#; + + let errors = build_errors("for_range_defer_ok", code).await; + assert!(errors.is_empty(), "expected no analyzer errors, actual: {:?}", errors); +} + +#[tokio::test] +async fn test_defer_forbid_control_flow_jumps() { + let code = r#" +fn main() { + defer { + return + } +} +"#; + + let errors = build_errors("defer_invalid_jump", code).await; + assert!( + errors + .iter() + .any(|msg| msg.contains("return/break/continue/throw/ret are not allowed inside defer block")), + "expected defer control-flow error, actual: {:?}", + errors + ); +} + +#[tokio::test] +async fn test_generic_method_interface_cannot_dynamic_dispatch() { + let code = r#" +type generic_dispatch = interface{ + fn id(T v):T +} + +fn main() { + generic_dispatch a = 1 +} +"#; + + let errors = build_errors("generic_interface_dispatch", code).await; + assert!( + errors.iter().any(|msg| msg.contains("cannot be used as dynamic dispatch")), + "expected object safety error, actual: {:?}", + errors + ); +} + +#[tokio::test] +async fn test_anyptr_can_assign_null_literal() { + let code = r#" +fn main() { + anyptr v = null +} +"#; + + let errors = build_errors("anyptr_null_literal", code).await; + assert!(errors.is_empty(), "expected no analyzer errors, actual: {:?}", errors); +} + +#[tokio::test] +async fn test_any_can_assign_null_literal() { + let code = r#" +fn main() { + any v = null +} +"#; + + let errors = build_errors("any_null_literal", code).await; + assert!(errors.is_empty(), "expected no analyzer errors, actual: {:?}", errors); +} + +#[tokio::test] +async fn test_impl_interface_checked_before_usage() { + let code = r#" +type measurable = interface{ + fn area():int + fn perimeter():int +} + +type rectangle: measurable = struct{ + int width + int height +} + +fn rectangle.area(&self):int { + return self.width * self.height +} + +fn main() {} +"#; + + let errors = build_errors("impl_interface_early_check", code).await; + assert!( + errors.iter().any(|msg| msg.contains("not impl fn 'perimeter' for interface")), + "expected impl-interface completeness error, actual: {:?}", + errors + ); +} diff --git a/runtime/allocator.c b/runtime/allocator.c index d14a06e2..0f9121a6 100644 --- a/runtime/allocator.c +++ b/runtime/allocator.c @@ -6,7 +6,8 @@ static uint8_t calc_sizeclass(uint64_t size) { // 快速路径:精确判断常见大小 if (size == 1) return 1; // class 1: 8 bytes if (size == 2) return 2; // class 2: 16 bytes, small structs (e.g. n_interface_t) - if (size == 40) return 5; // class 5: 48 bytes, n_string_t/n_vec_t + if (size == 40) return 5; // class 5: 48 bytes, n_string_t + if (size == 48) return 5; // class 5: 48 bytes, n_vec_t if (size == 56) return 6; // class 6: 64 bytes, n_map_t if (size == 128) return 10; // class 10: 128 bytes, map default space @@ -147,10 +148,10 @@ static page_summary_t chunk_summarize(page_chunk_t chunk) { if (combined == 0) { // 全部空闲的快速路径 - return (page_summary_t) { - .start = CHUNK_BITS_COUNT, - .max = CHUNK_BITS_COUNT, - .end = CHUNK_BITS_COUNT, + return (page_summary_t){ + .start = CHUNK_BITS_COUNT, + .max = CHUNK_BITS_COUNT, + .end = CHUNK_BITS_COUNT, }; } @@ -216,10 +217,10 @@ static page_summary_t chunk_summarize(page_chunk_t chunk) { max = current_free; } - return (page_summary_t) { - .start = start, - .max = max, - .end = end, + return (page_summary_t){ + .start = start, + .max = max, + .end = end, }; } @@ -418,8 +419,9 @@ static void chunks_set(addr_t base, uint64_t size, uint8_t value) { // 计算需要设置的位数量 uint64_t bit_count = bit_end - bit_start + 1; - DEBUGF("[runtime.chunks_set] chunk index: %lu, chunk block base: %p, bit_start: %lu, bit_end: %lu, bit_count: %lu", - index, (void *) chunk->blocks, bit_start, bit_end, bit_count); + DEBUGF( + "[runtime.chunks_set] chunk index: %lu, chunk block base: %p, bit_start: %lu, bit_end: %lu, bit_count: %lu", + index, (void *) chunk->blocks, bit_start, bit_end, bit_count); // 使用批量操作替代逐位设置,性能提升显著 if (value == 1) { @@ -464,9 +466,9 @@ uint64_t page_alloc_find(uint64_t pages_count, bool must_find) { page_alloc_t *page_alloc = &memory->mheap->page_alloc; DEBUGF( - "[runtime.page_alloc_find] will find continuous pages, l1 start=%lu, end=%lu, heap_used=%lu, pages_count=%lu", - start, end, - heap_used, pages_count); + "[runtime.page_alloc_find] will find continuous pages, l1 start=%lu, end=%lu, heap_used=%lu, pages_count=%lu", + start, end, + heap_used, pages_count); if (start == end) { if (must_find) { @@ -489,9 +491,9 @@ uint64_t page_alloc_find(uint64_t pages_count, bool must_find) { } DEBUGF( - "[runtime.page_alloc_find] level=%d, found=%d, start=%lu, end=%lu, start_summary=[%u, %u, %u], end_summary=[%u, %u, %u]", - level + 1, found, start, end, summaries[start].start, summaries[start].max, summaries[start].end, - summaries[end].start, summaries[end].max, summaries[end].end); + "[runtime.page_alloc_find] level=%d, found=%d, start=%lu, end=%lu, start_summary=[%u, %u, %u], end_summary=[%u, %u, %u]", + level + 1, found, start, end, summaries[start].start, summaries[start].max, summaries[start].end, + summaries[end].start, summaries[end].max, summaries[end].end); assert(found && "level zero find, next level must found"); // start ~ end 是当前 level 下的 index, 其在下一级的范围的 index为当前登记的 index * 8 @@ -502,10 +504,10 @@ uint64_t page_alloc_find(uint64_t pages_count, bool must_find) { } page_summary_t *lowest_summaries = page_alloc->summary[PAGE_SUMMARY_LEVEL - 1]; DEBUGF( - "[runtime.page_alloc_find] success find continuous pages(%lu), l5 start=%lu, end=%lu, start_summary=[%u, %u, %u], end_summary=[%u, %u, %u]", - pages_count, - start, end, lowest_summaries[start].start, lowest_summaries[start].max, lowest_summaries[start].end, - lowest_summaries[end].start, lowest_summaries[end].max, lowest_summaries[end].end); + "[runtime.page_alloc_find] success find continuous pages(%lu), l5 start=%lu, end=%lu, start_summary=[%u, %u, %u], end_summary=[%u, %u, %u]", + pages_count, + start, end, lowest_summaries[start].start, lowest_summaries[start].max, lowest_summaries[start].end, + lowest_summaries[end].start, lowest_summaries[end].max, lowest_summaries[end].end); // start 和 chunk 表示 chunk 的 index, // start ~ end 指向的一组 chunks 中包含连续的内存空间,现在需要确认起起点位置(假设 start == end, 其 可能是 start or mid or end @@ -571,8 +573,8 @@ uint64_t page_alloc_find(uint64_t pages_count, bool must_find) { find_addr = chunk_base(start) + bit_start * ALLOC_PAGE_SIZE; DEBUGF( - "[runtime.page_alloc_find] find addr=%p, start == end, start: %lu, chunk_base: %p, bit start: %lu, found: %d", - (void *) find_addr, start, chunk->blocks, bit_start, found); + "[runtime.page_alloc_find] find addr=%p, start == end, start: %lu, chunk_base: %p, bit start: %lu, found: %d", + (void *) find_addr, start, chunk->blocks, bit_start, found); // 更新从 find_addr 对应的 bit ~ page_count 位置的所有 chunk 的 bit 为 1 } else { @@ -582,8 +584,8 @@ uint64_t page_alloc_find(uint64_t pages_count, bool must_find) { // summary.end 表示 chunk 尾部可用的空间 uint64_t bit_start = CHUNK_BITS_COUNT - start_summary.end; // 512 - start_summary.end DEBUGF( - "[runtime.page_alloc_find] find addr=%p, start:%lu != end:%lu, start.summary [%d, %d, %d], bit_offset: %lu", - (void *) find_addr, start, end, start_summary.start, start_summary.max, start_summary.end, bit_start); + "[runtime.page_alloc_find] find addr=%p, start:%lu != end:%lu, start.summary [%d, %d, %d], bit_offset: %lu", + (void *) find_addr, start, end, start_summary.start, start_summary.max, start_summary.end, bit_start); find_addr = chunk_base(start) + bit_start * ALLOC_PAGE_SIZE; } assert(find_addr % ALLOC_PAGE_SIZE == 0 && "find addr not align_up"); @@ -679,7 +681,8 @@ void *mheap_sys_alloc(mheap_t *mheap, uint64_t *size) { } // 虚拟内存映射并不会真的写入到内存,必须触发内存页中断才行 - DEBUGF("[mheap_sys_alloc] allocate_total_bytes=%luMB, hint_addr=%p", allocated_total_bytes / 1024 / 1024, (void *) hint->addr); + DEBUGF("[mheap_sys_alloc] allocate_total_bytes=%luMB, hint_addr=%p", allocated_total_bytes / 1024 / 1024, + (void *) hint->addr); // reverse -> prepare sys_memory_map(v, alloc_size); @@ -706,10 +709,10 @@ static void mheap_set_spans(mspan_t *span) { // 判断当前 page_index 是否已经被其他 span 占用,如果占用了 DEBUGF( - "[mheap_set_spans] arena_base=%p page_index=%lu will set span=%p, span_base=%p, cursor_addr=%p, page_count=%lu", - (void *) arena->base, - page_index, span, (void *) span->base, (void *) cursor_addr, - span->pages_count); + "[mheap_set_spans] arena_base=%p page_index=%lu will set span=%p, span_base=%p, cursor_addr=%p, page_count=%lu", + (void *) arena->base, + page_index, span, (void *) span->base, (void *) cursor_addr, + span->pages_count); assert(arena->spans[page_index] == NULL && "span overlap"); @@ -880,9 +883,9 @@ static mspan_t *cache_span(mcentral_t *mcentral) { */ void uncache_span(mcentral_t *mcentral, mspan_t *span) { DEBUGF( - "[runtime.uncache_span] start, will lock mcentral=%p, span=%p, base=%p, spc=%d, obj_count=%lu, alloc_count=%lu", - mcentral, span, - (void *) span->base, span->spanclass, span->obj_count, span->alloc_count); + "[runtime.uncache_span] start, will lock mcentral=%p, span=%p, base=%p, spc=%d, obj_count=%lu, alloc_count=%lu", + mcentral, span, + (void *) span->base, span->spanclass, span->obj_count, span->alloc_count); mutex_lock(&mcentral->locker); // 如果 span 还有空闲则丢到 partial 否则丢到 full @@ -977,9 +980,10 @@ static addr_t mcache_alloc(uint8_t spanclass, mspan_t **span) { // 只有 GC 后回收的 span 才需要清零 if (mspan->needzero) { - DEBUGF("[runtime.mcache_alloc] p_index=%d, addr=%p need zero, obj_size=%lu", p->index, (void *) addr, mspan->obj_size); + DEBUGF("[runtime.mcache_alloc] p_index=%d, addr=%p need zero, obj_size=%lu", p->index, (void *) addr, + mspan->obj_size); memset((void *) addr, 0, mspan->obj_size); - + // 优化:如果整个 span 都分配完了,清除 needzero 标记 if (mspan->alloc_count == mspan->obj_count) { mspan->needzero = 0; @@ -1089,8 +1093,8 @@ static void heap_arena_bits_set(addr_t addr, uint64_t size, uint64_t obj_size, r } DEBUGF( - "[runtime.heap_arena_bits_set] rtype_kind=%s, size=%lu, scan_addr=0x%lx, temp_addr=0x%lx, bit_index=%ld, bit_value = %d", - type_kind_str[rtype->kind], size, addr, temp_addr, bit_index); + "[runtime.heap_arena_bits_set] rtype_kind=%s, size=%lu, scan_addr=0x%lx, temp_addr=0x%lx, bit_index=%ld, bit_value = %d", + type_kind_str[rtype->kind], size, addr, temp_addr, bit_index); index += 1; } @@ -1110,6 +1114,9 @@ static void heap_arena_bits_set(addr_t addr, uint64_t size, uint64_t obj_size, r // 单位 static addr_t std_malloc(uint64_t size, rtype_t *rtype) { + // assert 检测初始化 + assertf(memory, "gc memory uninitialized"); + DEBUGF("[std_malloc] start"); assert(size > 0); bool has_ptr = rtype != NULL && rtype->last_ptr > 0; @@ -1168,9 +1175,9 @@ static addr_t large_malloc(uint64_t size, rtype_t *rtype) { assert(span->obj_count == 1); bitmap_set(span->alloc_bits, 0); span->alloc_count += 1; - + if (span->needzero) { - memset((void *)span->base, 0, span->obj_size); + memset((void *) span->base, 0, span->obj_size); span->needzero = 0; } @@ -1181,11 +1188,11 @@ static addr_t large_malloc(uint64_t size, rtype_t *rtype) { debug_kind = type_kind_str[rtype->kind]; } DEBUGF( - "[runtime.large_malloc] success, spc=%d, span_base=%p, obj_size=%ld, need_size=%ld, type_kind=%s, " - "addr=%p,alloc_count=%lu,alloc_bit=%d, allocator_bytes=%ld", - span->spanclass, (void *) span->base, span->obj_size, size, debug_kind, (void *) span->base, - span->alloc_count, - bitmap_test(span->alloc_bits, 0), allocated_bytes); + "[runtime.large_malloc] success, spc=%d, span_base=%p, obj_size=%ld, need_size=%ld, type_kind=%s, " + "addr=%p,alloc_count=%lu,alloc_bit=%d, allocator_bytes=%ld", + span->spanclass, (void *) span->base, span->obj_size, size, debug_kind, (void *) span->base, + span->alloc_count, + bitmap_test(span->alloc_bits, 0), allocated_bytes); return span->base; } @@ -1296,11 +1303,14 @@ void memory_init() { // - 初始化 gcbits gcbits_areas_init(); - // links 数据反序列化,此时 rt_fndef_data rt_rtype_data 等数据可以正常使用 - DEBUGF("[memory_init] will start deserialize"); - DEBUGF("[memory_init] fndef count = %lu", rt_fndef_count); - DEBUGF("[memory_init] symdef count = %lu", rt_symdef_count); - DEBUGF("[memory_init] rtype count = %lu", rt_rtype_count); + memory->mheap = mheap; +} + +void runtime_deserialize_init() { + DEBUGF("[runtime_deserialize_init] will start deserialize"); + DEBUGF("[runtime_deserialize_init] fndef count = %lu", rt_fndef_count); + DEBUGF("[runtime_deserialize_init] symdef count = %lu", rt_symdef_count); + DEBUGF("[runtime_deserialize_init] rtype count = %lu", rt_rtype_count); nstrtable_deserialize(); ndata_deserialize(); @@ -1308,9 +1318,7 @@ void memory_init() { callers_deserialize(); rtypes_deserialize(); symdefs_deserialize(); - DEBUGF("[memory_init] deserialize success"); - - memory->mheap = mheap; + DEBUGF("[runtime_deserialize_init] deserialize success"); } mspan_t *span_of(addr_t addr) { @@ -1411,7 +1419,7 @@ mspan_t *mspan_new(uint64_t base, uint64_t pages_count, uint8_t spanclass) { // assert(bitmap_empty(span->alloc_bits, span->obj_count)); span->gcmark_bits = gcbits_new(span->obj_count); - + span->needzero = 0; DEBUGF("[mspan_new] success, base=%lx, pages_count=%lu, spc=%d, szc=%d, obj_size=%lu, obj_count=%lu", span->base, @@ -1478,9 +1486,10 @@ void *gc_malloc(uint64_t rhash) { assertf(rtype, "notfound rtype by hash=%ld", rhash); // uint64_t stage2 = uv_hrtime(); - DEBUGF("[gc_malloc] rhash=%lu, malloc size is %lu, last_ptr %lu, rtype bits: %s", rhash, rtype->heap_size, rtype->last_ptr, + DEBUGF("[gc_malloc] rhash=%lu, malloc size is %lu, last_ptr %lu, rtype bits: %s", rhash, rtype->heap_size, + rtype->last_ptr, bitmap_to_str(RTDATA(rtype->malloc_gc_bits_offset), - calc_gc_bits_size(rtype->heap_size, POINTER_SIZE))); + calc_gc_bits_size(rtype->heap_size, POINTER_SIZE))); void *result = rti_gc_malloc(rtype->gc_heap_size, rtype); DEBUGF("[gc_malloc] size %lu, value %p", rtype->heap_size, result); diff --git a/runtime/memory.c b/runtime/memory.c index d6dea72b..ac6f2c54 100644 --- a/runtime/memory.c +++ b/runtime/memory.c @@ -16,7 +16,7 @@ struct sc_map_sv const_str_pool; uint8_t gc_stage; // gc 阶段 mutex_t gc_stage_locker; -memory_t *memory; +memory_t *memory = NULL; void callers_deserialize() { sc_map_init_64v(&rt_caller_map, rt_caller_count * 2, 0); diff --git a/runtime/memory.h b/runtime/memory.h index 0ddd1f8c..4442990a 100644 --- a/runtime/memory.h +++ b/runtime/memory.h @@ -160,6 +160,8 @@ static inline uint64_t fetch_int_value(addr_t addr, uint64_t size) { void memory_init(); +void runtime_deserialize_init(); + /** * 基于 mmap * @param hint_addr diff --git a/runtime/nutils/nutils.c b/runtime/nutils/nutils.c index 3f7e17dc..738ea6ee 100644 --- a/runtime/nutils/nutils.c +++ b/runtime/nutils/nutils.c @@ -1,5 +1,8 @@ #include "nutils.h" +#include +#include + #include "array.h" #include "errort.h" #include "runtime/memory.h" @@ -12,17 +15,12 @@ int command_argc; char **command_argv; -static inline void panic_dump(coroutine_t *co, caller_t *caller, char *msg) { +static inline void panic_dump(caller_t *caller, char *msg) { // pre_rtcall_hook 中已经记录了 ret addr - char *dump_msg; uint64_t relpath_offset = ((fndef_t *) caller->data)->relpath_offset; - if (co->main) { - dump_msg = tlsprintf("coroutine 'main' panic: '%s' at %s:%d:%d\n", msg, - STRTABLE(relpath_offset), caller->line, caller->column); - } else { - dump_msg = tlsprintf("coroutine '%ld' panic: '%s' at %s:%d:%d\n", co->id, msg, - STRTABLE(relpath_offset), caller->line, caller->column); - } + char* dump_msg = tlsprintf("panic: '%s' at %s:%d:%d\n", msg, + STRTABLE(relpath_offset), caller->line, caller->column); + VOID write(STDOUT_FILENO, dump_msg, strlen(dump_msg)); // panic msg exit(EXIT_FAILURE); @@ -72,8 +70,8 @@ void interface_assert(n_interface_t *mu, int64_t target_rtype_hash, void *value_ void union_assert(n_union_t *mu, int64_t target_rtype_hash, void *value_ref) { if (mu->rtype->hash != target_rtype_hash) { DEBUGF("[union_assert] type assert failed, mu->rtype->kind: %s, target_rtype_hash: %ld", - type_kind_str[mu->rtype->kind], - target_rtype_hash); + type_kind_str[mu->rtype->kind], + target_rtype_hash); rti_throw("type assert failed", true); return; @@ -133,7 +131,8 @@ bool interface_is(n_interface_t *mu, int64_t target_rtype_hash) { * @param method_count * @param methods */ -void interface_casting(n_interface_t *out, uint64_t input_rtype_hash, void *value_ref, int64_t method_count, int64_t *methods) { +void interface_casting(n_interface_t *out, uint64_t input_rtype_hash, void *value_ref, int64_t method_count, + int64_t *methods) { assert(out && "interface_casting out is null"); // - 根据 input_rtype_hash 找到对应的 rtype_t *rtype = rt_find_rtype(input_rtype_hash); @@ -145,7 +144,7 @@ void interface_casting(n_interface_t *out, uint64_t input_rtype_hash, void *valu if (method_count > 0) { out->method_count = method_count; - out->methods = (int64_t *) rti_array_new(&uint64_rtype, method_count); + out->methods = (int64_t *) rti_array_new(&uint64_rtype, method_count); // TODO // 进行数据 copy TODO write barrier memmove(out->methods, methods, method_count * POINTER_SIZE); } else { @@ -223,7 +222,7 @@ void union_casting(n_union_t *out, int64_t input_rtype_hash, void *value_ref) { * @param value_ref * @return */ -void any_casting(n_any_t *out, int64_t input_rtype_hash, void *value_ref) { +void any_casting(n_any_t *out, int64_t input_rtype_hash, void *value_ref, n_bool_t is_fx) { assert(out && "any_casting out is null"); // - 根据 input_rtype_hash 找到对应的 rtype_t *rtype = rt_find_rtype(input_rtype_hash); @@ -242,9 +241,14 @@ void any_casting(n_any_t *out, int64_t input_rtype_hash, void *value_ref) { out->value.i64_value = 0; if (rtype->storage_kind == STORAGE_KIND_IND) { - void *new_value = rti_gc_malloc(rtype->gc_heap_size, rtype); - memmove(new_value, value_ref, storage_size); - out->value.ptr_value = new_value; + if (is_fx) { + // fx 模式下不进行 gc_malloc,直接引用原始地址。 + out->value.ptr_value = value_ref; + } else { + void *new_value = rti_gc_malloc(rtype->gc_heap_size, rtype); + memmove(new_value, value_ref, storage_size); + out->value.ptr_value = new_value; + } } else { memmove(&out->value, value_ref, storage_size); } @@ -256,7 +260,7 @@ void any_casting(n_any_t *out, int64_t input_rtype_hash, void *value_ref) { /** * union -> any: 提取 union 的 rtype 和 value 传递给 any_casting */ -void union_to_any(n_any_t *out, n_union_t *input) { +void union_to_any(n_any_t *out, n_union_t *input, n_bool_t is_fx) { assert(out && "union_to_any out is null"); assert(input && "union_to_any input is null"); assert(input->rtype && "union_to_any input rtype is null"); @@ -273,7 +277,7 @@ void union_to_any(n_any_t *out, n_union_t *input) { value_ref = &input->value; } - any_casting(out, rtype->hash, value_ref); + any_casting(out, rtype->hash, value_ref, is_fx); } void tagged_union_casting(n_tagged_union_t *out, int64_t tag_hash, int64_t value_rtype_hash, void *value_ref) { @@ -493,7 +497,7 @@ void co_throw_error(n_interface_t *error, char *path, char *fn_name, n_int_t lin void throw_index_out_error(n_int_t *index, n_int_t *len, n_bool_t be_catch) { coroutine_t *co = coroutine_get(); - addr_t ret_addr = CALLER_RET_ADDR(co); + addr_t ret_addr = CALLER_RET_ADDR(); assert(ret_addr); @@ -525,7 +529,7 @@ void throw_index_out_error(n_int_t *index, n_int_t *len, n_bool_t be_catch) { co->has_error = true; } else { char *copy_msg = strdup(msg); - panic_dump(co, caller, copy_msg); + panic_dump(caller, copy_msg); free(copy_msg); } } @@ -575,14 +579,8 @@ uint8_t co_has_panic(bool be_catch, char *path, char *fn_name, n_int_t line, n_i // 可以考虑增加 safepoint_lock, 避免进入 safepoint 状态 n_string_t msg = rti_error_msg(&co->error); - char *dump_msg; - if (co->main) { - dump_msg = tlsprintf("coroutine 'main' panic: '%s' at %s:%d:%d\n", (char *) rt_string_ref(&msg), - path, line, column); - } else { - dump_msg = tlsprintf("coroutine %ld panic: '%s' at %s:%d:%d\n", co->id, (char *) rt_string_ref(&msg), + char *dump_msg = tlsprintf("panic: '%s' at %s:%d:%d\n", (char *) rt_string_ref(&msg), path, line, column); - } VOID write(STDOUT_FILENO, dump_msg, strlen(dump_msg)); // panic msg @@ -756,14 +754,11 @@ void ptr_valid(void *ptr) { void rt_panic(n_string_t msg) { - coroutine_t *co = coroutine_get(); - n_processor_t *p = processor_get(); - - addr_t ret_addr = CALLER_RET_ADDR(co); + addr_t ret_addr = CALLER_RET_ADDR(); assert(ret_addr); caller_t *caller = sc_map_get_64v(&rt_caller_map, ret_addr); - panic_dump(co, caller, rt_string_ref(&msg)); + panic_dump(caller, rt_string_ref(&msg)); } bool rt_in_heap(n_anyptr_t addr) { @@ -772,19 +767,18 @@ bool rt_in_heap(n_anyptr_t addr) { void rt_assert(n_bool_t cond) { - coroutine_t *co = coroutine_get(); if (cond) { return; } // panic // 更新 ret addr 到 co 中 - addr_t ret_addr = CALLER_RET_ADDR(co); + addr_t ret_addr = CALLER_RET_ADDR(); assert(ret_addr); caller_t *caller = sc_map_get_64v(&rt_caller_map, ret_addr); assert(caller); - panic_dump(co, caller, "assertion failed"); + panic_dump(caller, "assertion failed"); } typedef struct { @@ -807,12 +801,6 @@ void rt_string_concat_out(n_string_t *out, n_string_t *a, n_string_t *b) { *out = string_concat(a, b); } -void rt_string_new_with_pool_out(n_string_t *out, void *raw_string, int64_t length) { - DEBUGF("[rt_string_new_with_pool_out] out %p, raw_string %s, len %ld", out, (char *) raw_string, length); - assert(out); - *out = string_new_with_pool(raw_string, length); -} - void rt_string_to_vec_out(n_vec_t *out, n_string_t *src) { assert(out); *out = string_to_vec(src); @@ -866,6 +854,27 @@ n_anyptr_t rt_array_new(int64_t element_hash, int64_t length) { return (n_anyptr_t) rti_array_new(element_rtype, (uint64_t) length); } +n_anyptr_t fx_malloc(int64_t size) { + if (size < 0) { + rti_throw("fx_malloc size must be non-negative", true); + return 0; + } + + if (size == 0) { + return 0; + } + + void *ptr = malloc((size_t) size); + if (!ptr) { + rti_throw("fx_malloc out of memory", true); + return 0; + } + DEBUGF("[fx_malloc] ptr is %p", ptr); + + memset(ptr, 0, (size_t) size); + return (n_anyptr_t) ptr; +} + n_vec_t unsafe_vec_new(int64_t hash, int64_t element_hash, int64_t len, void *data_ptr) { DEBUGF("[unsafe_vec_new] hash=%lu, element_hash=%lu, len=%lu, rhash, ele_rhash, length, capacity") assert(len > 0); diff --git a/runtime/nutils/nutils.h b/runtime/nutils/nutils.h index 752608c1..a9faac16 100644 --- a/runtime/nutils/nutils.h +++ b/runtime/nutils/nutils.h @@ -33,9 +33,9 @@ bool interface_is(n_interface_t *mu, int64_t target_rtype_hash); */ void union_casting(n_union_t *out, int64_t input_rtype_hash, void *value_ref); -void any_casting(n_any_t *out, int64_t input_rtype_hash, void *value_ref); +void any_casting(n_any_t *out, int64_t input_rtype_hash, void *value_ref, n_bool_t is_fx); -void union_to_any(n_any_t *out, n_union_t *input); +void union_to_any(n_any_t *out, n_union_t *input, n_bool_t is_fx); void tagged_union_casting(n_tagged_union_t *out, int64_t id, int64_t value_rtype_hash, void *value_ref); @@ -79,6 +79,7 @@ void rt_assert(n_bool_t cond); // allocate array data by element rtype hash n_anyptr_t rt_array_new(int64_t element_hash, int64_t length); +n_anyptr_t fx_malloc(int64_t size); n_vec_t unsafe_vec_new(int64_t hash, int64_t element_hash, int64_t len, void *data_ptr); @@ -92,7 +93,6 @@ n_string_t rt_string_new(n_anyptr_t raw_string); // LIR out-parameter helpers for builtin structs void rt_string_concat_out(n_string_t *out, n_string_t *a, n_string_t *b); -void rt_string_new_with_pool_out(n_string_t *out, void *raw_string, int64_t length); void rt_string_to_vec_out(n_vec_t *out, n_string_t *src); void rt_vec_to_string_out(n_string_t *out, n_vec_t *src); void rt_vec_slice_out(n_vec_t *out, n_vec_t *vec, int64_t start, int64_t end); diff --git a/runtime/nutils/vec.c b/runtime/nutils/vec.c index 0ef6d62e..706de90f 100644 --- a/runtime/nutils/vec.c +++ b/runtime/nutils/vec.c @@ -5,7 +5,7 @@ #include "utils/helper.h" static void rti_vec_grow(n_vec_t *vec, rtype_t *element_rtype, int custom_capacity) { - + void *old_data = vec->data; if (custom_capacity) { vec->capacity = custom_capacity; diff --git a/runtime/processor.c b/runtime/processor.c index 60b992f3..af1ba402 100644 --- a/runtime/processor.c +++ b/runtime/processor.c @@ -59,7 +59,7 @@ NO_OPTIMIZE void co_preempt_yield() { // 首次 preempt yield, 记录 ret_addr, 用于后续的 scan_stack 识别 if (assist_preempt_yield_ret_addr == 0) { - assist_preempt_yield_ret_addr = CALLER_RET_ADDR(co); + assist_preempt_yield_ret_addr = CALLER_RET_ADDR(); } n_processor_t *p = processor_get(); @@ -496,6 +496,10 @@ static void processor_wake(n_processor_t *p) { } void rt_coroutine_dispatch(coroutine_t *co) { + // 延迟初始化: 如果 fx 模式下需要协程调度,则初始化 fn 模式 + // fn_mode_init 内部有原子锁判断,重复调用安全 + fn_depend_init(false); + DEBUGF("[runtime.rt_coroutine_dispatch] co=%p, fn=%p, share_processor_count=%d", co, co->fn, cpu_count); // 分配 coroutine 之前需要给 coroutine 确认初始颜色, 如果是新增的 coroutine,默认都是黑色 @@ -537,7 +541,7 @@ void rt_coroutine_dispatch(coroutine_t *co) { /** * 各种全局变量初始化都通过该方法 */ -void sched_init() { +void sched_init(bool use_t0) { // - 初始化 aco 需要的 tls 变量(不能再线程中 create) aco_init(); @@ -586,7 +590,7 @@ void sched_init() { processor_index[p->index] = p; // P0 使用主线程,提前标记为已唤醒,避免 processor_wake 错误创建线程 - if (i == 0) { + if (use_t0 && i == 0) { p->thread_waked = true; } diff --git a/runtime/processor.h b/runtime/processor.h index 082714bb..64690494 100644 --- a/runtime/processor.h +++ b/runtime/processor.h @@ -229,7 +229,9 @@ void wait_all_gc_work_finished(); * runtime_main 会负责调用该方法,该方法读取 cpu 的核心数,然后初始化对应数量的 share_processor * 每个 share_processor 可以通过 void* arg 直接找到自己的 share_processor_t 对象 */ -void sched_init(); +void sched_init(bool use_t0); + +void fn_depend_init(bool use_t0); void sched_run(); diff --git a/runtime/rtype.c b/runtime/rtype.c index c8971c5b..eb71340c 100644 --- a/runtime/rtype.c +++ b/runtime/rtype.c @@ -11,7 +11,7 @@ rtype_t string_element_rtype = {0}; // 添加 hash table gc_rtype(TYPE_UINT64, 0); rtype_t uint64_rtype = {0}; -// 添加 hash table (GC_RTYPE(TYPE_STRING, 5, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN);) +// 添加 hash table (GC_RTYPE(TYPE_STRING, 6, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN);) rtype_t string_rtype = {0}; rtype_t string_ref_rtype = {0}; @@ -36,7 +36,7 @@ rtype_t std_arg_rtype = {0}; // GC_RTYPE(TYPE_STRING, 2, TYPE_GC_SCAN, TYPE_GC_NOSCAN); rtype_t os_env_rtype = {0}; -// GC_RTYPE(TYPE_VEC, 5, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN) +// GC_RTYPE(TYPE_VEC, 6, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN) rtype_t vec_rtype = {0}; // GC_RTYPE(TYPE_GC_FN, 12, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, @@ -56,4 +56,4 @@ void *rt_find_data(int64_t offset) { void *rt_find_strtable(int64_t offset) { return STRTABLE(offset); -} \ No newline at end of file +} diff --git a/runtime/rtype.h b/runtime/rtype.h index 9e6b4320..eecea7ec 100644 --- a/runtime/rtype.h +++ b/runtime/rtype.h @@ -17,7 +17,7 @@ extern rtype_t string_element_rtype; // 添加 hash table gc_rtype(TYPE_UINT64, 0); extern rtype_t uint64_rtype; -// 添加 hash table (GC_RTYPE(TYPE_STRING, 5, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN);) +// 添加 hash table (GC_RTYPE(TYPE_STRING, 6, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN);) extern rtype_t string_rtype; // 默认会被 rtypes_deserialize 覆盖为 compile 中的值 @@ -42,7 +42,7 @@ extern rtype_t std_arg_rtype; // GC_RTYPE(TYPE_STRING, 2, TYPE_GC_SCAN, TYPE_GC_NOSCAN); extern rtype_t os_env_rtype; -// GC_RTYPE(TYPE_VEC, 5, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN) +// GC_RTYPE(TYPE_VEC, 6, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN) extern rtype_t vec_rtype; extern rtype_t fn_rtype; @@ -89,12 +89,12 @@ static inline rtype_t rti_rtype_array(rtype_t *element_rtype, uint64_t length) { assert(element_rtype); rtype_t rtype = { - .gc_heap_size = element_rtype->storage_size * length, - .hash = 0, // runtime 生成的没有 hash 值,不需要进行 hash 定位 - .kind = TYPE_ARR, - .length = length, - .malloc_gc_bits_offset = -1, - .hashes_offset = -1, + .gc_heap_size = element_rtype->storage_size * length, + .hash = 0, // runtime 生成的没有 hash 值,不需要进行 hash 定位 + .kind = TYPE_ARR, + .length = length, + .malloc_gc_bits_offset = -1, + .hashes_offset = -1, }; rtype.last_ptr = element_rtype->last_ptr > 0; // 根据 0 和 1 在 heap_arena_bits_set 进行特殊处理 @@ -116,12 +116,12 @@ static inline void builtin_rtype_init() { sc_map_put_64v(&rt_rtype_map, uint64_rtype.hash, &uint64_rtype); // 初始化字符串 rtype - string_rtype = GC_RTYPE(TYPE_STRING, 5, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, - TYPE_GC_NOSCAN); + string_rtype = GC_RTYPE(TYPE_STRING, 6, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, + TYPE_GC_NOSCAN, TYPE_GC_NOSCAN); sc_map_put_64v(&rt_rtype_map, string_rtype.hash, &string_rtype); - string_ref_rtype = GC_RTYPE(TYPE_STRING, 5, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, - TYPE_GC_NOSCAN); + string_ref_rtype = GC_RTYPE(TYPE_STRING, 6, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, + TYPE_GC_NOSCAN, TYPE_GC_NOSCAN); sc_map_put_64v(&rt_rtype_map, string_rtype.hash, &string_rtype); // 测试 gc_bits @@ -131,9 +131,11 @@ static inline void builtin_rtype_init() { assert(bitmap_test((uint8_t *) &string_rtype.gc_bits, 3) == 0); // 初始化错误追踪 rtype - errort_trace_rtype = GC_RTYPE(TYPE_STRUCT, 12, + errort_trace_rtype = GC_RTYPE(TYPE_STRUCT, 14, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, + TYPE_GC_NOSCAN, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, + TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN); sc_map_put_64v(&rt_rtype_map, errort_trace_rtype.hash, &errort_trace_rtype); @@ -161,7 +163,8 @@ static inline void builtin_rtype_init() { os_env_rtype = GC_RTYPE(TYPE_STRING, 2, TYPE_GC_SCAN, TYPE_GC_NOSCAN); // 初始化向量 rtype - vec_rtype = GC_RTYPE(TYPE_VEC, 5, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN); + vec_rtype = GC_RTYPE(TYPE_VEC, 6, TYPE_GC_SCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, TYPE_GC_NOSCAN, + TYPE_GC_NOSCAN); // 初始化函数 rtype fn_rtype = GC_RTYPE(TYPE_FN, 2, TYPE_GC_SCAN, TYPE_GC_NOSCAN); diff --git a/runtime/runtime.c b/runtime/runtime.c index 9be52cd5..601ddf0c 100644 --- a/runtime/runtime.c +++ b/runtime/runtime.c @@ -1,5 +1,6 @@ #include "runtime.h" +#include #include #include "nutils/http.h" @@ -13,41 +14,72 @@ extern void user_main(void) __asm("_main.main"); extern void user_main(void) __asm("main.main"); #endif +static _Atomic bool fn_mode_inited = false; + /** - * crt1.o _start -> main -> entry + * fn 模式初始化,包含内存、调度器、协程等初始化 + * 内部包含原子锁判断,重复调用安全 */ -int runtime_main(int argc, char *argv[]) { - // - read arg - DEBUGF("[runtime_main] start, argc=%d, argv=%p", argc, argv); - command_argc = argc; - command_argv = argv; +void fn_depend_init(bool use_t0) { + bool expected = false; + if (!atomic_compare_exchange_strong(&fn_mode_inited, &expected, true)) { + return; // 已初始化 + } + + RDEBUGF("[fn_depend_init] start"); // - heap memory init memory_init(); - RDEBUGF("[runtime_main] memory init success"); + RDEBUGF("[fn_depend_init] memory init success"); - // - env clsoure + // - env closure env_upvalue_table = table_new(); mutex_init(&env_upvalue_locker, false); - sched_init(); - RDEBUGF("[runtime_main] processor init success"); + sched_init(use_t0); + RDEBUGF("[fn_depend_init] sched init success"); // register const pool register_const_str_pool(); - // - 提取 main 进行 coroutine 创建调度,需要等待 processor init 加载完成 - coroutine_t *main_co = rt_coroutine_new((void *) user_main, FLAG(CO_FLAG_MAIN) | FLAG(CO_FLAG_DIRECT), NULL, NULL); - rt_coroutine_dispatch(main_co); - RDEBUGF("[runtime_main] main_co dispatch success") - - // 等待 processor init 注册完成运行后再启动 sysmon 进行抢占式调度 + // 启动 sysmon 进行抢占式调度 wait_sysmond(); + RDEBUGF("[fn_depend_init] complete"); +} + +/** + * crt1.o _start -> main -> entry + */ +int runtime_main(int argc, char *argv[]) { + // - read arg + DEBUGF("[runtime_main] start, argc=%d, argv=%p, main_is_fn %d", argc, argv, user_main_is_fn()); + command_argc = argc; + command_argv = argv; + + // 两种模式都需要 deserialize + runtime_deserialize_init(); + RDEBUGF("[runtime_main] deserialize init success"); + + if (user_main_is_fn()) { + // fn 模式:初始化调度器,使用协程运行 + fn_depend_init(true); + + // - 提取 main 进行 coroutine 创建调度 + coroutine_t *main_co = rt_coroutine_new((void *) user_main, FLAG(CO_FLAG_MAIN) | FLAG(CO_FLAG_DIRECT), NULL, + NULL); + rt_coroutine_dispatch(main_co); + RDEBUGF("[runtime_main] main_co dispatch success"); - // - wait_sysmon - sched_run(); + // - sched_run + sched_run(); - DEBUGF("[runtime_main] user code run completed,will exit"); + DEBUGF("[runtime_main] fn mode user code run completed, will exit"); + } else { + // fx 模式:直接调用 user_main,无需 GC 和调度器 + DEBUGF("[runtime_main] fx mode, calling user_main directly"); + user_main(); + DEBUGF("[runtime_main] fx mode user code run completed, will exit"); + } return 0; } diff --git a/runtime/runtime.h b/runtime/runtime.h index f066f821..6a115b5f 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -34,16 +34,22 @@ int runtime_main(int argc, char *argv[]) __asm("main"); #endif #endif +extern uint8_t main_is_fn; + +static inline bool user_main_is_fn(void) { + return main_is_fn != 0; +} + #ifdef __AMD64 -#define CALLER_RET_ADDR(_co) \ +#define CALLER_RET_ADDR() \ ({ \ uint64_t _rbp_value; \ __asm__ volatile("mov %%rbp, %0" : "=r"(_rbp_value)); \ fetch_addr_value(_rbp_value + POINTER_SIZE); \ }); #elif defined(__ARM64) -#define CALLER_RET_ADDR(_co) \ +#define CALLER_RET_ADDR() \ ({ \ addr_t _fp_value; \ __asm__ volatile("mov %0, x29" : "=r"(_fp_value)); \ @@ -51,7 +57,7 @@ int runtime_main(int argc, char *argv[]) __asm("main"); _value; \ }); #elif defined(__RISCV64) -#define CALLER_RET_ADDR(_co) \ +#define CALLER_RET_ADDR() \ ({ \ addr_t _fp_value; \ __asm__ volatile("mv %0, s0" : "=r"(_fp_value)); \ diff --git a/src/ast.c b/src/ast.c index 4f62fbc9..427c5bb5 100644 --- a/src/ast.c +++ b/src/ast.c @@ -760,7 +760,12 @@ static ast_for_cond_stmt_t *ast_for_cond_copy(module_t *m, ast_for_cond_stmt_t * static ast_for_iterator_stmt_t *ast_for_iterator_copy(module_t *m, ast_for_iterator_stmt_t *temp) { ast_for_iterator_stmt_t *stmt = COPY_NEW(ast_for_iterator_stmt_t, temp); - stmt->iterate = *ast_expr_copy(m, &temp->iterate); + if (temp->is_range) { + stmt->range_start = *ast_expr_copy(m, &temp->range_start); + stmt->range_end = *ast_expr_copy(m, &temp->range_end); + } else { + stmt->iterate = *ast_expr_copy(m, &temp->iterate); + } stmt->first = *ast_var_decl_copy(m, &temp->first); stmt->second = temp->second ? ast_var_decl_copy(m, temp->second) : NULL; stmt->body = ast_body_copy(m, temp->body); @@ -862,6 +867,13 @@ static ast_stmt_t *ast_stmt_copy(module_t *m, ast_stmt_t *temp) { stmt->value = ast_return_copy(m, temp->value); break; } + case AST_STMT_DEFER: { + ast_defer_stmt_t *temp_stmt = temp->value; + ast_defer_stmt_t *defer_stmt = COPY_NEW(ast_defer_stmt_t, temp_stmt); + defer_stmt->body = ast_body_copy(m, temp_stmt->body); + stmt->value = defer_stmt; + break; + } case AST_CALL: { stmt->value = ast_call_copy(m, temp->value); break; diff --git a/src/ast.h b/src/ast.h index 46974de9..77f9927d 100644 --- a/src/ast.h +++ b/src/ast.h @@ -77,6 +77,7 @@ typedef enum { AST_STMT_IF, AST_STMT_THROW, AST_STMT_LET, + AST_STMT_DEFER, AST_STMT_FOR_ITERATOR, AST_STMT_FOR_COND, AST_STMT_FOR_TRADITION, @@ -237,6 +238,7 @@ typedef struct { list_t *args; // *ast_expr bool spread; + bool inject_self_arg; } ast_call_t; typedef struct { @@ -448,6 +450,12 @@ typedef struct { */ typedef struct { ast_expr_t iterate; // list, foo.list, bar[0] + + // for i in start..end {} + bool is_range; + ast_expr_t range_start; + ast_expr_t range_end; + ast_var_decl_t first; // 类型推导, type 可能是 int 或者 string ast_var_decl_t *second; // value 可选,可能为 null slice_t *body; @@ -457,6 +465,10 @@ typedef struct { ast_expr_t *expr; } ast_return_stmt_t; +typedef struct { + slice_t *body; // ast_stmt +} ast_defer_stmt_t; + // Selective import item: {sqrt, pow, Pi as pi} typedef struct { char *ident; // symbol name to import @@ -724,6 +736,7 @@ struct ast_fndef_t { bool is_impl; // 是否是 impl fn // impl fn without self receiver bool is_static; + bool is_fx; // 是否是 fx mode bool is_errable; @@ -734,7 +747,7 @@ struct ast_fndef_t { // 当 self_kind == PARAM_SELF_T 时,interface 存储指针数据但方法期望值类型 // receiver_wrapper 用于接收指针参数,解引用后调用原函数 - struct ast_fndef_t *receiver_wrapper; + char *receiver_wrapper_ident; bool is_generics; // 是否是泛型 @@ -937,6 +950,7 @@ static inline ast_fndef_t *ast_fndef_new(module_t *m, int line, int column) { fndef->ret_target_types = stack_new(); fndef->generics_params = NULL; fndef->is_impl = false; + fndef->is_fx = false; fndef->capture_exprs = ct_list_new(sizeof(ast_expr_t)); fndef->be_capture_locals = slice_new(); diff --git a/src/astgen.h b/src/astgen.h new file mode 100644 index 00000000..7d97cd82 --- /dev/null +++ b/src/astgen.h @@ -0,0 +1,64 @@ +#ifndef NATURE_SRC_ASTGEN_H_ +#define NATURE_SRC_ASTGEN_H_ + +#include "ast.h" + +static inline ast_for_tradition_stmt_t *astgen_for_range_rewrite(ast_for_iterator_stmt_t *for_iter) { + int line = for_iter->range_start.line; + int column = for_iter->range_start.column; + if (line <= 0) { + line = for_iter->range_end.line; + column = for_iter->range_end.column; + } + + ast_for_tradition_stmt_t *rewrite = NEW(ast_for_tradition_stmt_t); + + ast_stmt_t *init = NEW(ast_stmt_t); + init->line = line; + init->column = column; + init->assert_type = AST_STMT_VARDEF; + ast_vardef_stmt_t *init_vardef = NEW(ast_vardef_stmt_t); + init_vardef->var_decl = for_iter->first; + init_vardef->right = NEW(ast_expr_t); + *init_vardef->right = for_iter->range_start; + init->value = init_vardef; + + ast_expr_t cond = { + .line = line, + .column = column, + .assert_type = AST_EXPR_BINARY, + }; + ast_binary_expr_t *cond_binary = NEW(ast_binary_expr_t); + cond_binary->op = AST_OP_LT; + cond_binary->left = *ast_ident_expr(line, column, for_iter->first.ident); + cond_binary->right = for_iter->range_end; + cond.value = cond_binary; + + ast_stmt_t *update = NEW(ast_stmt_t); + update->line = line; + update->column = column; + update->assert_type = AST_STMT_ASSIGN; + ast_assign_stmt_t *update_assign = NEW(ast_assign_stmt_t); + update_assign->left = *ast_ident_expr(line, column, for_iter->first.ident); + + ast_expr_t update_right = { + .line = line, + .column = column, + .assert_type = AST_EXPR_BINARY, + }; + ast_binary_expr_t *update_binary = NEW(ast_binary_expr_t); + update_binary->op = AST_OP_ADD; + update_binary->left = *ast_ident_expr(line, column, for_iter->first.ident); + update_binary->right = *ast_int_expr(line, column, 1); + update_right.value = update_binary; + update_assign->right = update_right; + update->value = update_assign; + + rewrite->init = init; + rewrite->cond = cond; + rewrite->update = update; + rewrite->body = for_iter->body; + return rewrite; +} + +#endif // NATURE_SRC_ASTGEN_H_ diff --git a/src/build/build.c b/src/build/build.c index 96e3ab3b..be9af032 100644 --- a/src/build/build.c +++ b/src/build/build.c @@ -29,6 +29,7 @@ #include "src/semantic/analyzer.h" #include "src/semantic/global_eval.h" #include "src/semantic/generics.h" +#include "src/semantic/interface.h" #include "src/semantic/infer.h" #include "src/ssa.h" #include "utils/helper.h" @@ -40,6 +41,7 @@ // char*, 支持 .o 或者 .a 文件后缀 static slice_t *linker_libs; +static uint8_t build_main_is_fn = 1; /** * base on ${NATURE_ROOT}/lib/${BUILD_OS}_${BUILD_ARCH} + file @@ -164,6 +166,8 @@ static void elf_custom_links() { elf_put_global_symbol(ctx, F64_NEG_MASK_IDENT, &f64_mask, QWORD); float f32_mast = (float) (-0.0); elf_put_global_symbol(ctx, F32_NEG_MASK_IDENT, &f32_mast, DWORD); + uint8_t main_is_fn = build_main_is_fn; + elf_put_global_symbol(ctx, SYMBOL_MAIN_IS_FN, &main_is_fn, BYTE); elf_file_format(ctx); @@ -262,6 +266,8 @@ static void mach_custom_links() { macho_put_global_symbol(ctx, F64_NEG_MASK_IDENT, &f64_mask, QWORD); float f32_mast = (float) (-0.0); macho_put_global_symbol(ctx, F32_NEG_MASK_IDENT, &f32_mast, DWORD); + uint8_t main_is_fn = build_main_is_fn; + macho_put_global_symbol(ctx, SYMBOL_MAIN_IS_FN, &main_is_fn, BYTE); mach_output_object(ctx); log_debug(" --> assembler: %s\n", custom_link_object_path()); @@ -939,8 +945,6 @@ static slice_t *build_modules(toml_table_t *package_conf) { linked_push(work_list, main_package); - table_t *import_tpl_table = table_new(); - while (work_list->count > 0) { // module_build time has perfected import module_t *m = linked_pop(work_list); @@ -987,6 +991,17 @@ static slice_t *build_modules(toml_table_t *package_conf) { analyzer(m, m->stmt_list); } + // 查找 main 函数 + ast_fndef_t *main_fndef = NULL; + SLICE_FOR(main_package->ast_fndefs) { + ast_fndef_t *f = SLICE_VALUE(main_package->ast_fndefs); + if (str_equal(f->fn_name, FN_MAIN_NAME)) { + main_fndef = f; + } + } + assert(main_fndef); + build_main_is_fn = main_fndef->is_fx ? 0 : 1; + return modules; } @@ -1071,6 +1086,13 @@ static void build_compiler(slice_t *modules) { generics(m); } + // interface pass + // 在 generics 之后,先校验 type impl interface 约束 + for (int i = modules->count - 1; i >= 0; --i) { + module_t *m = modules->take[i]; + interface(m); + } + // pre infer pass // 优先处理 builtin_module for (int i = modules->count - 1; i >= 0; --i) { @@ -1094,15 +1116,14 @@ static void build_compiler(slice_t *modules) { for (int i = modules->count - 1; i >= 0; --i) { module_t *m = modules->take[i]; global_eval(m); + + infer(m); } // infer + compiler for (int i = 0; i < modules->count; ++i) { module_t *m = modules->take[i]; - // 类型推断 - infer(m); - // 编译为 lir linear(m); diff --git a/src/debug/debug.c b/src/debug/debug.c index 2da68ccf..05f3a264 100644 --- a/src/debug/debug.c +++ b/src/debug/debug.c @@ -26,6 +26,7 @@ string ast_type_to_str[] = { [AST_STMT_GLOBAL_ASSIGN] = "AST_STMT_GLOBAL_ASSIGN", [AST_STMT_RETURN] = "AST_STMT_RETURN", [AST_STMT_IF] = "AST_STMT_IF", + [AST_STMT_DEFER] = "AST_STMT_DEFER", [AST_STMT_FOR_ITERATOR] = "AST_STMT_FOR_ITERATOR", [AST_FNDEF] = "AST_FUNCTION_DECL", [AST_CALL] = "AST_CALL", @@ -118,9 +119,11 @@ string token_type_to_str[] = { // [TOKEN_ARRAY]="TOKEN_ARRAY", // [TOKEN_MAP]="TOKEN_MAP", [TOKEN_FN] = "TOKEN_FN", + [TOKEN_FX] = "TOKEN_FX", [TOKEN_IMPORT] = "TOKEN_IMPORT", [TOKEN_AS] = "TOKEN_AS", - [TOKEN_RETURN] = "TOKEN_RETURN"}; + [TOKEN_RETURN] = "TOKEN_RETURN", + [TOKEN_DEFER] = "TOKEN_DEFER"}; string lir_opcode_to_string[] = { [LIR_OPCODE_ADD] = "ADD ", diff --git a/src/linear.c b/src/linear.c index ba765016..78db5410 100644 --- a/src/linear.c +++ b/src/linear.c @@ -9,47 +9,168 @@ #include "utils/linked.h" lir_opcode_t ast_op_convert[] = { - [AST_OP_ADD] = LIR_OPCODE_ADD, - [AST_OP_SUB] = LIR_OPCODE_SUB, - [AST_OP_MUL] = LIR_OPCODE_MUL, // 默认有符号 - [AST_OP_DIV] = LIR_OPCODE_SDIV, - [AST_OP_REM] = LIR_OPCODE_SREM, - - [AST_OP_LSHIFT] = LIR_OPCODE_USHL, - [AST_OP_RSHIFT] = LIR_OPCODE_SSHR, // 默认进行有符号,linear 进行调整 - [AST_OP_AND] = LIR_OPCODE_AND, - [AST_OP_OR] = LIR_OPCODE_OR, - [AST_OP_XOR] = LIR_OPCODE_XOR, - - [AST_OP_LT] = LIR_OPCODE_SLT, - [AST_OP_LE] = LIR_OPCODE_SLE, - [AST_OP_GT] = LIR_OPCODE_SGT, - [AST_OP_GE] = LIR_OPCODE_SGE, - [AST_OP_EE] = LIR_OPCODE_SEE, - [AST_OP_NE] = LIR_OPCODE_SNE, - - [AST_OP_BNOT] = LIR_OPCODE_NOT, - [AST_OP_NEG] = LIR_OPCODE_NEG, + [AST_OP_ADD] = LIR_OPCODE_ADD, + [AST_OP_SUB] = LIR_OPCODE_SUB, + [AST_OP_MUL] = LIR_OPCODE_MUL, // 默认有符号 + [AST_OP_DIV] = LIR_OPCODE_SDIV, + [AST_OP_REM] = LIR_OPCODE_SREM, + + [AST_OP_LSHIFT] = LIR_OPCODE_USHL, + [AST_OP_RSHIFT] = LIR_OPCODE_SSHR, // 默认进行有符号,linear 进行调整 + [AST_OP_AND] = LIR_OPCODE_AND, + [AST_OP_OR] = LIR_OPCODE_OR, + [AST_OP_XOR] = LIR_OPCODE_XOR, + + [AST_OP_LT] = LIR_OPCODE_SLT, + [AST_OP_LE] = LIR_OPCODE_SLE, + [AST_OP_GT] = LIR_OPCODE_SGT, + [AST_OP_GE] = LIR_OPCODE_SGE, + [AST_OP_EE] = LIR_OPCODE_SEE, + [AST_OP_NE] = LIR_OPCODE_SNE, + + [AST_OP_BNOT] = LIR_OPCODE_NOT, + [AST_OP_NEG] = LIR_OPCODE_NEG, }; lir_opcode_t ast_op_to_for_continue[] = { - [AST_OP_LT] = LIR_OPCODE_BLT, - [AST_OP_LE] = LIR_OPCODE_BLE, - [AST_OP_GT] = LIR_OPCODE_BGT, - [AST_OP_GE] = LIR_OPCODE_BGE, - [AST_OP_EE] = LIR_OPCODE_BEE, - [AST_OP_NE] = LIR_OPCODE_BNE, + [AST_OP_LT] = LIR_OPCODE_BLT, + [AST_OP_LE] = LIR_OPCODE_BLE, + [AST_OP_GT] = LIR_OPCODE_BGT, + [AST_OP_GE] = LIR_OPCODE_BGE, + [AST_OP_EE] = LIR_OPCODE_BEE, + [AST_OP_NE] = LIR_OPCODE_BNE, }; lir_opcode_t ast_op_to_if_alert[] = { - [AST_OP_LT] = LIR_OPCODE_BGE, - [AST_OP_LE] = LIR_OPCODE_BGT, - [AST_OP_GT] = LIR_OPCODE_BLE, - [AST_OP_GE] = LIR_OPCODE_BLT, - [AST_OP_EE] = LIR_OPCODE_BNE, - [AST_OP_NE] = LIR_OPCODE_BEE, + [AST_OP_LT] = LIR_OPCODE_BGE, + [AST_OP_LE] = LIR_OPCODE_BGT, + [AST_OP_GT] = LIR_OPCODE_BLE, + [AST_OP_GE] = LIR_OPCODE_BLT, + [AST_OP_EE] = LIR_OPCODE_BNE, + [AST_OP_NE] = LIR_OPCODE_BEE, }; +typedef struct { + slice_t *defer_stmts; // ast_defer_stmt_t* + uint16_t continue_depth; + uint16_t break_depth; + uint16_t ret_depth; + uint16_t catch_depth; +} linear_defer_scope_t; + +typedef enum { + LINEAR_UNWIND_MODE_ALL = 1, + LINEAR_UNWIND_MODE_BREAK, + LINEAR_UNWIND_MODE_CONTINUE, + LINEAR_UNWIND_MODE_RET, + LINEAR_UNWIND_MODE_CATCH, +} linear_unwind_mode_t; + +static linear_defer_scope_t *linear_defer_scope_new(module_t *m) { + linear_defer_scope_t *scope = NEW(linear_defer_scope_t); + scope->defer_stmts = slice_new(); + scope->continue_depth = m->current_closure->continue_labels->count; + scope->break_depth = m->current_closure->break_labels->count; + scope->ret_depth = m->current_closure->ret_labels->count; + scope->catch_depth = m->current_closure->catch_error_labels->count; + return scope; +} + +static void linear_emit_defer_stmt(module_t *m, ast_defer_stmt_t *defer_stmt); + +static void linear_emit_scope_defer_stmts(module_t *m, linear_defer_scope_t *scope) { + for (int i = scope->defer_stmts->count - 1; i >= 0; --i) { + ast_defer_stmt_t *defer_stmt = scope->defer_stmts->take[i]; + linear_emit_defer_stmt(m, defer_stmt); + } +} + +static void linear_defer_scope_enter(module_t *m) { + linear_defer_scope_t *scope = linear_defer_scope_new(m); + stack_push(m->current_closure->defer_scopes, scope); +} + +static void linear_defer_scope_leave(module_t *m) { + linear_defer_scope_t *scope = stack_pop(m->current_closure->defer_scopes); + if (!scope) { + return; + } + linear_emit_scope_defer_stmts(m, scope); +} + +static void linear_defer_register(module_t *m, ast_defer_stmt_t *defer_stmt) { + linear_defer_scope_t *scope = stack_top(m->current_closure->defer_scopes); + LINEAR_ASSERTF(scope, "defer must be in a lexical scope"); + slice_push(scope->defer_stmts, defer_stmt); +} + +static void linear_emit_defer_stmt(module_t *m, ast_defer_stmt_t *defer_stmt) { + linear_body(m, defer_stmt->body); +} + +static bool linear_scope_need_unwind(linear_defer_scope_t *scope, linear_unwind_mode_t mode, uint16_t depth) { + switch (mode) { + case LINEAR_UNWIND_MODE_ALL: { + return true; + } + case LINEAR_UNWIND_MODE_BREAK: { + return scope->break_depth >= depth; + } + case LINEAR_UNWIND_MODE_CONTINUE: { + return scope->continue_depth >= depth; + } + case LINEAR_UNWIND_MODE_RET: { + return scope->ret_depth >= depth; + } + case LINEAR_UNWIND_MODE_CATCH: { + return scope->catch_depth >= depth; + } + default: { + return false; + } + } +} + +static void linear_unwind_scopes(module_t *m, linear_unwind_mode_t mode, uint16_t depth) { + ct_stack_t *defer_scopes = m->current_closure->defer_scopes; + if (stack_empty(defer_scopes)) { + return; + } + + for (stack_node *node = defer_scopes->top->next; node != NULL; node = node->next) { + linear_defer_scope_t *scope = node->value; + if (!linear_scope_need_unwind(scope, mode, depth)) { + continue; + } + linear_emit_scope_defer_stmts(m, scope); + } +} + +static void linear_unwind_all(module_t *m) { + linear_unwind_scopes(m, LINEAR_UNWIND_MODE_ALL, 0); +} + +static void linear_unwind_to_break_depth(module_t *m, uint16_t depth) { + linear_unwind_scopes(m, LINEAR_UNWIND_MODE_BREAK, depth); +} + +static void linear_unwind_to_continue_depth(module_t *m, uint16_t depth) { + linear_unwind_scopes(m, LINEAR_UNWIND_MODE_CONTINUE, depth); +} + +static void linear_unwind_to_ret_depth(module_t *m, uint16_t depth) { + linear_unwind_scopes(m, LINEAR_UNWIND_MODE_RET, depth); +} + +static void linear_unwind_to_catch_depth(module_t *m, uint16_t depth) { + linear_unwind_scopes(m, LINEAR_UNWIND_MODE_CATCH, depth); +} + +static void linear_bal_error(module_t *m, char *error_target_label, uint16_t catch_depth) { + linear_unwind_to_catch_depth(m, catch_depth); + OP_PUSH(lir_op_bal(lir_label_operand(error_target_label, true))); +} + static lir_operand_t * linear_inline_arr_element_addr_not_check(module_t *m, lir_operand_t *arr_target, lir_operand_t *index_target, type_t arr_type) { @@ -102,15 +223,15 @@ linear_inline_arr_element_addr(module_t *m, lir_operand_t *arr_target, lir_opera // TODO 共用 index out error handle label, 也就是有错误直接 goto 到这个地方,而不需要生成成百上千个 char *error_label_ident = m->current_closure->error_label; - bool be_catch = false; - if (!stack_empty(m->current_closure->catch_error_labels)) { + uint16_t catch_depth = m->current_closure->catch_error_labels->count; + bool be_catch = catch_depth > 0; + if (be_catch) { error_label_ident = stack_top(m->current_closure->catch_error_labels); - be_catch = true; } push_rt_call(m, RT_CALL_THROW_INDEX_OUT_ERROR, NULL, 3, index_target, length_target, bool_operand(be_catch)); // bal catch or end label - OP_PUSH(lir_op_bal(lir_label_operand(error_label_ident, true))); + linear_bal_error(m, error_label_ident, catch_depth); OP_PUSH(lir_op_label(end_label_ident, true)); int64_t element_size = arr_type.array->element_type.storage_size; @@ -207,15 +328,15 @@ linear_inline_vec_element_addr(module_t *m, lir_operand_t *vec_target, lir_opera OP_PUSH(lir_op_new(LIR_OPCODE_BEE, bool_operand(true), cmp_result, cmp_end_label)); char *error_label_ident = m->current_closure->error_label; - bool be_catch = false; - if (!stack_empty(m->current_closure->catch_error_labels)) { + uint16_t catch_depth = m->current_closure->catch_error_labels->count; + bool be_catch = catch_depth > 0; + if (be_catch) { error_label_ident = stack_top(m->current_closure->catch_error_labels); - be_catch = true; } push_rt_call(m, RT_CALL_THROW_INDEX_OUT_ERROR, NULL, 3, index_target, length_target, bool_operand(be_catch)); // bal catch or end label - OP_PUSH(lir_op_bal(lir_label_operand(error_label_ident, true))); + linear_bal_error(m, error_label_ident, catch_depth); OP_PUSH(lir_op_label(end_label_ident, true)); int64_t element_size = vec_element_type.storage_size; @@ -301,6 +422,30 @@ static lir_operand_t *linear_default_string(module_t *m, type_t t, lir_operand_t return target; } +static lir_operand_t *linear_string(module_t *m, type_t t, lir_operand_t *raw_string, int64_t length, + lir_operand_t *target) { + if (!target) { + target = temp_var_operand_with_alloc(m, t); + } + + lir_operand_t *data_dst = indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), target, offsetof(n_string_t, data)); + lir_operand_t *len_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_string_t, length)); + lir_operand_t *cap_dst = + indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_string_t, capacity)); + lir_operand_t *elem_size_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, + offsetof(n_string_t, element_size)); + lir_operand_t *hash_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_string_t, hash)); + + // string 是不可变对象,literal 可以直接引用 .data 段 raw_string + OP_PUSH(lir_op_move(data_dst, raw_string)); + OP_PUSH(lir_op_move(len_dst, int_operand(length))); + OP_PUSH(lir_op_move(cap_dst, int_operand(length + 1))); + OP_PUSH(lir_op_move(elem_size_dst, int_operand(type_kind_sizeof(TYPE_UINT8)))); + OP_PUSH(lir_op_move(hash_dst, int_operand(type_hash(t)))); + + return target; +} + static lir_operand_t *linear_default_nullable(module_t *m, type_t t, lir_operand_t *target) { type_t null_type = type_kind_new(TYPE_NULL); uint64_t rtype_hash = type_hash(null_type); @@ -341,7 +486,8 @@ static lir_operand_t *linear_default_any(module_t *m, type_t t, lir_operand_t *t out_src = lea_operand_pointer(m, target); } OP_PUSH(lir_op_move(out_ptr, out_src)); - push_rt_call(m, RT_CALL_ANY_CASTING, NULL, 3, out_ptr, int_operand(rtype_hash), value_ref); + bool is_fx = m->current_closure && m->current_closure->is_fx; + push_rt_call(m, RT_CALL_ANY_CASTING, NULL, 4, out_ptr, int_operand(rtype_hash), value_ref, bool_operand(is_fx)); return target; } @@ -358,12 +504,15 @@ linear_default_vec(module_t *m, type_t t, lir_operand_t *target) { lir_operand_t *elem_size_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_vec_t, element_size)); lir_operand_t *hash_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_vec_t, hash)); + lir_operand_t *allocator_dst = indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), target, + offsetof(n_vec_t, allocator)); OP_PUSH(lir_op_move(data_dst, int_operand(0))); OP_PUSH(lir_op_move(len_dst, int_operand(0))); OP_PUSH(lir_op_move(cap_dst, int_operand(0))); OP_PUSH(lir_op_move(elem_size_dst, int_operand(t.vec->element_type.storage_size))); OP_PUSH(lir_op_move(hash_dst, int_operand(type_hash(t)))); + OP_PUSH(lir_op_move(allocator_dst, int_operand(0))); return target; } @@ -393,19 +542,66 @@ linear_unsafe_vec_new(module_t *m, type_t t, uint64_t len, lir_operand_t *target lir_operand_t *elem_size_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_vec_t, element_size)); lir_operand_t *hash_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_vec_t, hash)); + lir_operand_t *allocator_dst = indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), target, + offsetof(n_vec_t, allocator)); OP_PUSH(lir_op_move(len_dst, int_operand(len))); OP_PUSH(lir_op_move(cap_dst, int_operand(len))); OP_PUSH(lir_op_move(elem_size_dst, int_operand(t.vec->element_type.storage_size))); OP_PUSH(lir_op_move(hash_dst, int_operand(type_hash(t)))); + OP_PUSH(lir_op_move(allocator_dst, int_operand(0))); if (len == 0) { OP_PUSH(lir_op_move(data_dst, int_operand(0))); } else { lir_operand_t *data_ptr = temp_var_operand_with_alloc(m, type_kind_new(TYPE_ANYPTR)); - lir_operand_t *element_hash = int_operand(type_hash(t.vec->element_type)); - lir_operand_t *len_operand = int_operand(len); - push_rt_call(m, RT_CALL_ARRAY_NEW, data_ptr, 2, element_hash, len_operand); + assert(m->current_closure); + if (m->current_closure->is_fx) { + uint64_t data_size = len * t.vec->element_type.storage_size; + push_rt_call(m, RT_CALL_FX_MALLOC, data_ptr, 1, int_operand(data_size)); + } else { + lir_operand_t *element_hash = int_operand(type_hash(t.vec->element_type)); + lir_operand_t *len_operand = int_operand(len); + push_rt_call(m, RT_CALL_ARRAY_NEW, data_ptr, 2, element_hash, len_operand); + } + OP_PUSH(lir_op_move(data_dst, data_ptr)); + } + + return target; +} + +static lir_operand_t * +linear_stack_vec_new(module_t *m, type_t t, uint64_t len, lir_operand_t *target) { + if (!target) { + target = temp_var_operand_with_alloc(m, t); + } + assert(target->assert_type == LIR_OPERAND_VAR); + + lir_operand_t *data_dst = indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), target, offsetof(n_vec_t, data)); + lir_operand_t *len_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_vec_t, length)); + lir_operand_t *cap_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_vec_t, capacity)); + lir_operand_t *elem_size_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, + offsetof(n_vec_t, element_size)); + lir_operand_t *hash_dst = indirect_addr_operand(m, type_kind_new(TYPE_INT64), target, offsetof(n_vec_t, hash)); + lir_operand_t *allocator_dst = indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), target, + offsetof(n_vec_t, allocator)); + + OP_PUSH(lir_op_move(len_dst, int_operand(len))); + OP_PUSH(lir_op_move(cap_dst, int_operand(len))); + OP_PUSH(lir_op_move(elem_size_dst, int_operand(t.vec->element_type.storage_size))); + OP_PUSH(lir_op_move(hash_dst, int_operand(type_hash(t)))); + OP_PUSH(lir_op_move(allocator_dst, int_operand(0))); + + if (len == 0) { + OP_PUSH(lir_op_move(data_dst, int_operand(0))); + } else { + type_array_t *data_array = NEW(type_array_t); + data_array->length = len; + data_array->element_type = t.vec->element_type; + type_t data_array_type = type_new(TYPE_ARR, data_array); + + lir_operand_t *data_target = temp_var_operand_with_alloc(m, data_array_type); + lir_operand_t *data_ptr = lea_operand_pointer(m, data_target); OP_PUSH(lir_op_move(data_dst, data_ptr)); } @@ -673,10 +869,10 @@ static void linear_has_panic(module_t *m) { assertf(m->current_column < 1000000, "column '%d' exception", m->current_line); // panic 必须被立刻 catch, 判断当前表达式是否被 catch, 如果被 catch, 则走正常的 error 流程, 也就是有错误跳转到 catch label - bool be_catch = false; - if (!stack_empty(m->current_closure->catch_error_labels)) { + uint16_t catch_depth = m->current_closure->catch_error_labels->count; + bool be_catch = catch_depth > 0; + if (be_catch) { error_target_label = stack_top(m->current_closure->catch_error_labels); - be_catch = true; } lir_operand_t *path_operand = string_operand(m->rel_path, strlen(m->rel_path)); @@ -692,7 +888,14 @@ static void linear_has_panic(module_t *m) { line_operand, column_operand); - OP_PUSH(lir_op_new(LIR_OPCODE_BEE, bool_operand(true), has_error, lir_label_operand(error_target_label, true))); + char *panic_ident = label_ident_with_unique(".panic"); + char *panic_end_ident = str_connect(panic_ident, LABEL_END_SUFFIX); + + OP_PUSH(lir_op_new(LIR_OPCODE_BEE, bool_operand(true), has_error, lir_label_operand(panic_ident, true))); + OP_PUSH(lir_op_bal(lir_label_operand(panic_end_ident, true))); + OP_PUSH(lir_op_label(panic_ident, true)); + linear_bal_error(m, error_target_label, catch_depth); + OP_PUSH(lir_op_label(panic_end_ident, true)); } @@ -702,7 +905,8 @@ static void linear_has_error(module_t *m) { assertf(m->current_column < 1000000, "column '%d' exception", m->current_line); // 存在 catch error - if (!stack_empty(m->current_closure->catch_error_labels)) { + uint16_t catch_depth = m->current_closure->catch_error_labels->count; + if (catch_depth > 0) { error_target_label = stack_top(m->current_closure->catch_error_labels); } @@ -717,7 +921,14 @@ static void linear_has_error(module_t *m) { // 不可抢占,也不 yield,所以不需要添加任何勾子。 push_rt_call(m, RT_CALL_CO_HAS_ERROR, has_error, 4, path_operand, fn_name_operand, line_operand, column_operand); - OP_PUSH(lir_op_new(LIR_OPCODE_BEE, bool_operand(true), has_error, lir_label_operand(error_target_label, true))); + + char *error_ident = label_ident_with_unique(".error"); + char *error_end_ident = str_connect(error_ident, LABEL_END_SUFFIX); + OP_PUSH(lir_op_new(LIR_OPCODE_BEE, bool_operand(true), has_error, lir_label_operand(error_ident, true))); + OP_PUSH(lir_op_bal(lir_label_operand(error_end_ident, true))); + OP_PUSH(lir_op_label(error_ident, true)); + linear_bal_error(m, error_target_label, catch_depth); + OP_PUSH(lir_op_label(error_end_ident, true)); } /** @@ -977,8 +1188,8 @@ static lir_operand_t *linear_inline_env_values(module_t *m) { // mov [env+0] -> values lir_operand_t *values_operand = temp_var_operand(m, type_kind_new(TYPE_GC_ENV_VALUES)); OP_PUSH( - lir_op_move(values_operand, - indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), m->current_closure->env_operand, 0))); + lir_op_move(values_operand, + indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), m->current_closure->env_operand, 0))); return values_operand; } @@ -1547,18 +1758,23 @@ static void linear_for_tradition(module_t *m, ast_for_tradition_stmt_t *ast) { static void linear_continue(module_t *m) { LINEAR_ASSERTF(m->current_closure->continue_labels->count > 0, "continue must use in for stmt") + uint16_t continue_depth = m->current_closure->continue_labels->count; lir_operand_t *label = stack_top(m->current_closure->continue_labels); + linear_unwind_to_continue_depth(m, continue_depth); OP_PUSH(lir_op_bal(label)); } static void linear_break(module_t *m) { LINEAR_ASSERTF(m->current_closure->break_labels->count > 0, "break must use in for stmt body"); + uint16_t break_depth = m->current_closure->break_labels->count; lir_operand_t *label = stack_top(m->current_closure->break_labels); + linear_unwind_to_break_depth(m, break_depth); OP_PUSH(lir_op_bal(label)); } static void linear_ret(module_t *m, ast_ret_stmt_t *stmt) { LINEAR_ASSERTF(m->current_closure->ret_labels->count > 0, "ret must use in match body"); + uint16_t ret_depth = m->current_closure->ret_labels->count; lir_operand_t *label = stack_top(m->current_closure->ret_labels); // stmt->expr type maybe void, like println() @@ -1567,22 +1783,19 @@ static void linear_ret(module_t *m, ast_ret_stmt_t *stmt) { linear_expr(m, stmt->expr, target); } + linear_unwind_to_ret_depth(m, ret_depth); OP_PUSH(lir_op_new(LIR_OPCODE_RET, NULL, NULL, label)); OP_PUSH(lir_op_bal(label)); } static void linear_return(module_t *m, ast_return_stmt_t *ast) { + lir_operand_t *src = NULL; if (ast->expr != NULL) { - lir_operand_t *src = linear_expr(m, *ast->expr, NULL); - // return void_expr() 时, m->linear_current->return_operand 是 null - // if (m->current_closure->return_operand) { - // linear_super_move(m, ast->expr->type, m->current_closure->return_operand, src); - // } - - // 保留用来做 return check - OP_PUSH(lir_op_new(LIR_OPCODE_RETURN, src, NULL, NULL)); + src = linear_expr(m, *ast->expr, NULL); } + linear_unwind_all(m); + OP_PUSH(lir_op_new(LIR_OPCODE_RETURN, src, NULL, NULL)); OP_PUSH(lir_op_bal(lir_label_operand(m->current_closure->end_label, false))); } @@ -1863,7 +2076,10 @@ static lir_operand_t *linear_call(module_t *m, ast_expr_t expr, lir_operand_t *t // actual 剩余的所有参数进行 linear_expr 之后 都需要用一个数组收集起来,并写入到 target_operand 中 int len = call->args->length - i; // 5, 1 - lir_operand_t *rest_vec_target = linear_unsafe_vec_new(m, *rest_list_type, len, NULL); + bool is_fx = m->current_closure && m->current_closure->is_fx; + lir_operand_t *rest_vec_target = is_fx + ? linear_stack_vec_new(m, *rest_list_type, len, NULL) + : linear_unsafe_vec_new(m, *rest_list_type, len, NULL); type_t vec_element_type = rest_list_type->vec->element_type; int index = 0; @@ -1874,7 +2090,7 @@ static lir_operand_t *linear_call(module_t *m, ast_expr_t expr, lir_operand_t *t // no check lir_operand_t *index_target = int_operand(index); lir_operand_t *arg_dst_target = linear_inline_vec_element_addr_no_check(m, rest_vec_target, - index_target, vec_element_type); + index_target, vec_element_type); // 基于 vec_element_type 判断 assign 的 item 类型 if (is_gc_alloc(vec_element_type.kind)) { @@ -1917,8 +2133,8 @@ static lir_operand_t *linear_call(module_t *m, ast_expr_t expr, lir_operand_t *t OP_PUSH(lir_op_move(env_target, indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), fn_target, 0))); OP_PUSH( - lir_op_move(new_fn_target, - indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), fn_target, POINTER_SIZE))); + lir_op_move(new_fn_target, + indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), fn_target, POINTER_SIZE))); fn_target = new_fn_target; slice_push(args, env_target); @@ -2271,7 +2487,7 @@ static lir_operand_t *linear_vec_new(module_t *m, ast_expr_t expr, lir_operand_t lir_operand_t *index_target = int_operand(i); lir_operand_t *item_dst_target = linear_inline_vec_element_addr_no_check(m, vec_target, index_target, - vec_element_type); + vec_element_type); lir_operand_t *item_src_target = linear_expr(m, *item_expr, NULL); @@ -2897,10 +3113,10 @@ static lir_operand_t *linear_reflect_hash_expr(module_t *m, ast_expr_t expr, lir static lir_operand_t *linear_is_expr(module_t *m, ast_expr_t expr, lir_operand_t *target) { ast_is_expr_t *is_expr = expr.value; assert(is_expr->src->type.kind == TYPE_UNION || - is_expr->src->type.kind == TYPE_PTR || - is_expr->src->type.kind == TYPE_TAGGED_UNION || - is_expr->src->type.kind == TYPE_INTERFACE || - is_expr->src->type.kind == TYPE_ANY); + is_expr->src->type.kind == TYPE_PTR || + is_expr->src->type.kind == TYPE_TAGGED_UNION || + is_expr->src->type.kind == TYPE_INTERFACE || + is_expr->src->type.kind == TYPE_ANY); if (!target) { target = temp_var_operand_with_alloc(m, expr.type); @@ -3026,7 +3242,8 @@ static lir_operand_t *linear_as_expr(module_t *m, ast_expr_t expr, lir_operand_t lir_operand_t *union_ptr = temp_var_operand(m, type_kind_new(TYPE_ANYPTR)); OP_PUSH(lir_op_move(union_ptr, src_operand)); - push_rt_call(m, RT_CALL_UNION_TO_ANY, NULL, 2, out_ptr, union_ptr); + bool is_fx = m->current_closure && m->current_closure->is_fx; + push_rt_call(m, RT_CALL_UNION_TO_ANY, NULL, 3, out_ptr, union_ptr, bool_operand(is_fx)); return target; } @@ -3049,7 +3266,9 @@ static lir_operand_t *linear_as_expr(module_t *m, ast_expr_t expr, lir_operand_t out_src = lea_operand_pointer(m, target); } OP_PUSH(lir_op_move(out_ptr, out_src)); - push_rt_call(m, RT_CALL_ANY_CASTING, NULL, 3, out_ptr, int_operand(src_rtype_hash), any_value); + bool is_fx = m->current_closure && m->current_closure->is_fx; + push_rt_call(m, RT_CALL_ANY_CASTING, NULL, 4, out_ptr, int_operand(src_rtype_hash), any_value, + bool_operand(is_fx)); return target; } @@ -3210,11 +3429,11 @@ static lir_operand_t *linear_as_expr(module_t *m, ast_expr_t expr, lir_operand_t symbol_t *fn_symbol = symbol_table_get(fn_ident); assert(fn_symbol); - if (ast_fndef->receiver_wrapper) { - symbol_t *wrapper_fn_symbol = symbol_table_get(ast_fndef->receiver_wrapper->symbol_name); + if (ast_fndef->receiver_wrapper_ident) { + symbol_t *wrapper_fn_symbol = symbol_table_get(ast_fndef->receiver_wrapper_ident); assert(wrapper_fn_symbol); - ast_fndef = ast_fndef->receiver_wrapper; + ast_fndef = wrapper_fn_symbol->ast_value; fn_ident = ast_fndef->symbol_name; } @@ -3547,16 +3766,8 @@ static void linear_try_catch_stmt(module_t *m, ast_try_catch_stmt_t *try_stmt) { static lir_operand_t *linear_literal(module_t *m, ast_expr_t expr, lir_operand_t *target) { ast_literal_t *literal = expr.value; if (literal->kind == TYPE_STRING) { - if (!target) { - target = temp_var_operand_with_alloc(m, expr.type); - } - lir_operand_t *out_ptr = linear_lea_builtin_value_struct(m, target); - - // 转换成 nature string 对象(基于 string_new), 转换的结果赋值给 target lir_operand_t *imm_c_string_operand = string_operand(literal->value, literal->len); - lir_operand_t *imm_len_operand = int_operand(literal->len); - push_rt_call(m, RT_CALL_STRING_NEW_WITH_POOL, NULL, 3, out_ptr, imm_c_string_operand, imm_len_operand); - return target; + return linear_string(m, expr.type, imm_c_string_operand, literal->len, target); } if (literal->kind == TYPE_NULL) { @@ -3733,7 +3944,7 @@ static lir_operand_t *linear_fn_decl(module_t *m, ast_expr_t expr, lir_operand_t // dst addr lir_operand_t *values_operand = temp_var_operand_with_alloc(m, type_kind_new(TYPE_GC_ENV_VALUES)); OP_PUSH(lir_op_move(values_operand, - indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), env_operand, 0))); + indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), env_operand, 0))); // src_ptr 一定是一个指针类型的地址, 比如 PTR/STRING/VEC 等等,所以此处可以直接使用 TYPE_ANYPTR lir_operand_t *dst = indirect_addr_operand(m, type_kind_new(TYPE_ANYPTR), values_operand, @@ -3779,6 +3990,8 @@ static void linear_throw(module_t *m, ast_throw_stmt_t *stmt) { line_operand, column_operand); + linear_unwind_all(m); + // 插入 return 标识(用来做 return check 的,check 完会清除的) OP_PUSH(lir_op_new(LIR_OPCODE_RETURN, NULL, NULL, NULL)); @@ -3830,11 +4043,12 @@ static void linear_stmt(module_t *m, ast_stmt_t *stmt) { } case AST_FNDEF: { linear_fn_decl(m, - (ast_expr_t) { - .line = stmt->line, - .assert_type = stmt->assert_type, - .value = stmt->value, - .target_type = NULL}, + (ast_expr_t){ + .line = stmt->line, + .assert_type = stmt->assert_type, + .value = stmt->value, + .target_type = NULL + }, NULL); return; } @@ -3842,13 +4056,13 @@ static void linear_stmt(module_t *m, ast_stmt_t *stmt) { ast_call_t *call = stmt->value; // stmt 中都 call 都是没有返回值的 linear_call(m, - (ast_expr_t) { - .line = stmt->line, - .column = stmt->column, - .assert_type = AST_CALL, - .type = call->return_type, - .target_type = call->return_type, - .value = call, + (ast_expr_t){ + .line = stmt->line, + .column = stmt->column, + .assert_type = AST_CALL, + .type = call->return_type, + .target_type = call->return_type, + .value = call, }, NULL); return; @@ -3856,13 +4070,13 @@ static void linear_stmt(module_t *m, ast_stmt_t *stmt) { case AST_CATCH: { ast_catch_t *catch = stmt->value; linear_catch_expr(m, - (ast_expr_t) { - .line = stmt->line, - .column = stmt->column, - .assert_type = AST_CATCH, - .type = catch->try_expr.type, - .target_type = catch->try_expr.type, - .value = catch, + (ast_expr_t){ + .line = stmt->line, + .column = stmt->column, + .assert_type = AST_CATCH, + .type = catch->try_expr.type, + .target_type = catch->try_expr.type, + .value = catch, }, NULL); return; @@ -3873,6 +4087,10 @@ static void linear_stmt(module_t *m, ast_stmt_t *stmt) { case AST_STMT_RETURN: { return linear_return(m, stmt->value); } + case AST_STMT_DEFER: { + linear_defer_register(m, stmt->value); + return; + } case AST_STMT_THROW: { return linear_throw(m, stmt->value); } @@ -3911,11 +4129,11 @@ static lir_operand_t *linear_ternary(module_t *m, ast_expr_t expr, lir_operand_t if (ternary->condition.type.kind == TYPE_BOOL) { // For bool: branch to else if false OP_PUSH(lir_op_new(LIR_OPCODE_BEE, bool_operand(false), cond_operand, - lir_label_operand(else_label, true))); + lir_label_operand(else_label, true))); } else { // For ptr/anyptr: branch to else if null (compare with 0) OP_PUSH(lir_op_new(LIR_OPCODE_BEE, int_operand(0), cond_operand, - lir_label_operand(else_label, true))); + lir_label_operand(else_label, true))); } // Consequent branch: evaluate 'then' expression and move to target @@ -3935,38 +4153,38 @@ static lir_operand_t *linear_ternary(module_t *m, ast_expr_t expr, lir_operand_t } linear_expr_fn expr_fn_table[] = { - [AST_EXPR_LITERAL] = linear_literal, - [AST_EXPR_IDENT] = linear_ident, - [AST_EXPR_ENV_ACCESS] = linear_env_access, - [AST_EXPR_BINARY] = linear_binary, - [AST_EXPR_UNARY] = linear_unary, - [AST_EXPR_TERNARY] = linear_ternary, - [AST_EXPR_ARRAY_NEW] = linear_array_new, - [AST_EXPR_ARRAY_REPEAT_NEW] = linear_array_repeat_new, - [AST_EXPR_ARRAY_ACCESS] = linear_array_access, - [AST_EXPR_VEC_NEW] = linear_vec_new, - [AST_EXPR_VEC_ACCESS] = linear_vec_access, - [AST_EXPR_VEC_SLICE] = linear_vec_slice, - [AST_EXPR_MAP_NEW] = linear_map_new, - [AST_EXPR_MAP_ACCESS] = linear_map_access, - [AST_EXPR_STRUCT_NEW] = linear_struct_new, - [AST_EXPR_STRUCT_SELECT] = linear_struct_select, - [AST_EXPR_TUPLE_NEW] = linear_tuple_new, - [AST_EXPR_TAGGED_UNION_NEW] = linear_tagged_union_new, - [AST_EXPR_TUPLE_ACCESS] = linear_tuple_access, - [AST_EXPR_SET_NEW] = linear_set_new, - [AST_CALL] = linear_call, - [AST_FNDEF] = linear_fn_decl, - [AST_EXPR_AS] = linear_as_expr, - [AST_EXPR_IS] = linear_is_expr, - [AST_MACRO_EXPR_DEFAULT] = linear_default_expr, - [AST_MACRO_EXPR_SIZEOF] = linear_sizeof_expr, - [AST_MACRO_EXPR_REFLECT_HASH] = linear_reflect_hash_expr, - [AST_MACRO_ASYNC] = linear_macro_async, - [AST_EXPR_NEW] = linear_new_expr, - [AST_CATCH] = linear_catch_expr, - [AST_MATCH] = linear_match_expr, - [AST_EXPR_BLOCK] = linear_block_expr, + [AST_EXPR_LITERAL] = linear_literal, + [AST_EXPR_IDENT] = linear_ident, + [AST_EXPR_ENV_ACCESS] = linear_env_access, + [AST_EXPR_BINARY] = linear_binary, + [AST_EXPR_UNARY] = linear_unary, + [AST_EXPR_TERNARY] = linear_ternary, + [AST_EXPR_ARRAY_NEW] = linear_array_new, + [AST_EXPR_ARRAY_REPEAT_NEW] = linear_array_repeat_new, + [AST_EXPR_ARRAY_ACCESS] = linear_array_access, + [AST_EXPR_VEC_NEW] = linear_vec_new, + [AST_EXPR_VEC_ACCESS] = linear_vec_access, + [AST_EXPR_VEC_SLICE] = linear_vec_slice, + [AST_EXPR_MAP_NEW] = linear_map_new, + [AST_EXPR_MAP_ACCESS] = linear_map_access, + [AST_EXPR_STRUCT_NEW] = linear_struct_new, + [AST_EXPR_STRUCT_SELECT] = linear_struct_select, + [AST_EXPR_TUPLE_NEW] = linear_tuple_new, + [AST_EXPR_TAGGED_UNION_NEW] = linear_tagged_union_new, + [AST_EXPR_TUPLE_ACCESS] = linear_tuple_access, + [AST_EXPR_SET_NEW] = linear_set_new, + [AST_CALL] = linear_call, + [AST_FNDEF] = linear_fn_decl, + [AST_EXPR_AS] = linear_as_expr, + [AST_EXPR_IS] = linear_is_expr, + [AST_MACRO_EXPR_DEFAULT] = linear_default_expr, + [AST_MACRO_EXPR_SIZEOF] = linear_sizeof_expr, + [AST_MACRO_EXPR_REFLECT_HASH] = linear_reflect_hash_expr, + [AST_MACRO_ASYNC] = linear_macro_async, + [AST_EXPR_NEW] = linear_new_expr, + [AST_CATCH] = linear_catch_expr, + [AST_MATCH] = linear_match_expr, + [AST_EXPR_BLOCK] = linear_block_expr, }; static lir_operand_t *linear_expr(module_t *m, ast_expr_t expr, lir_operand_t *target) { @@ -3981,6 +4199,8 @@ static lir_operand_t *linear_expr(module_t *m, ast_expr_t expr, lir_operand_t *t } static void linear_body(module_t *m, slice_t *body) { + linear_defer_scope_enter(m); + for (int i = 0; i < body->count; ++i) { ast_stmt_t *stmt = body->take[i]; #ifdef DEBUG_linear @@ -3988,6 +4208,8 @@ static void linear_body(module_t *m, slice_t *body) { #endif linear_stmt(m, stmt); } + + linear_defer_scope_leave(m); } /** @@ -4034,7 +4256,9 @@ static closure_t *linear_fndef(module_t *m, ast_fndef_t *fndef) { OP_PUSH(lir_op_output(LIR_OPCODE_FN_BEGIN, operand_new(LIR_OPERAND_PARAMS, params))); - OP_PUSH(lir_op_safepoint()); + if (!fndef->is_fx) { + OP_PUSH(lir_op_safepoint()); + } // 参数 escape rewrite for (int i = 0; i < fndef->params->length; ++i) { @@ -4077,6 +4301,7 @@ void linear(module_t *m) { } closure_t *closure = linear_fndef(fndef->module, fndef); + assert(m == closure->module); slice_push(m->closures, closure); } } diff --git a/src/lir.c b/src/lir.c index eed4f9c1..c3779e34 100644 --- a/src/lir.c +++ b/src/lir.c @@ -26,6 +26,7 @@ closure_t *lir_closure_new(ast_fndef_t *fndef) { c->ret_labels = stack_new(); c->continue_labels = stack_new(); c->break_labels = stack_new(); + c->defer_scopes = stack_new(); c->ssa_globals = slice_new(); c->ssa_globals_table = table_new(); @@ -49,6 +50,7 @@ closure_t *lir_closure_new(ast_fndef_t *fndef) { c->interval_count = alloc_reg_count() + 1; fndef->closure = c; + c->is_fx = fndef->is_fx; c->fndef = fndef; c->stack_gc_bits = bitmap_new(1024); diff --git a/src/lir.h b/src/lir.h index 5bc431a2..23868529 100644 --- a/src/lir.h +++ b/src/lir.h @@ -126,7 +126,6 @@ #define RT_CALL_ENV_ASSIGN_REF "env_assign_ref" // 实际代码位置对 env 的访问 #define RT_CALL_ENV_ELEMENT_VALUE "env_element_value" // heap addr -#define RT_CALL_STRING_NEW "string_new" #define RT_CALL_STRING_TO_VEC "rt_string_to_vec_out" #define RT_CALL_VEC_TO_STRING "rt_vec_to_string_out" #define RT_CALL_STRING_NEW_WITH_POOL "rt_string_new_with_pool_out" @@ -142,6 +141,7 @@ #define RT_CALL_STRING_REF "rt_string_ref" // 默认引用传递 #define RT_CALL_GC_MALLOC "gc_malloc" +#define RT_CALL_FX_MALLOC "fx_malloc" #define RT_CALL_RUNTIME_EVAL_GC "runtime_eval_gc" @@ -264,13 +264,12 @@ static inline bool is_rtcall(string target) { str_equal(target, RT_CALL_ITERATOR_TAKE_VALUE) || str_equal(target, RT_CALL_FN_NEW) || str_equal(target, RT_CALL_ENV_NEW) || str_equal(target, RT_CALL_ENV_ASSIGN_REF) || str_equal(target, RT_CALL_ENV_ELEMENT_VALUE) || - str_equal(target, RT_CALL_STRING_NEW) || str_equal(target, RT_CALL_STRING_NEW_WITH_POOL) || str_equal(target, RT_CALL_STRING_CONCAT) || str_equal(target, RT_CALL_STRING_TO_VEC) || str_equal(target, RT_CALL_VEC_TO_STRING) || str_equal(target, RT_CALL_VEC_SLICE) || str_equal(target, RT_CALL_STRING_EE) || str_equal(target, RT_CALL_STRING_NE) || str_equal(target, RT_CALL_STRING_LT) || str_equal(target, RT_CALL_STRING_LE) || str_equal(target, RT_CALL_STRING_GT) || str_equal(target, RT_CALL_STRING_GE) || - str_equal(target, RT_CALL_GC_MALLOC) || + str_equal(target, RT_CALL_GC_MALLOC) || str_equal(target, RT_CALL_FX_MALLOC) || str_equal(target, RT_CALL_RUNTIME_EVAL_GC) || str_equal(target, RT_CALL_COROUTINE_ASYNC2) || str_equal(target, RT_CALL_CO_THROW_ERROR) || str_equal(target, RT_CALL_CO_REMOVE_ERROR) || str_equal(target, RT_CALL_CO_HAS_ERROR) || str_equal(target, RT_CALL_CO_HAS_PANIC) || str_equal(target, RT_CALL_PROCESSOR_SET_EXIT) || diff --git a/src/module.c b/src/module.c index 7492d95d..988b7bc7 100644 --- a/src/module.c +++ b/src/module.c @@ -105,19 +105,19 @@ module_t *module_build(ast_import_t *import, char *source_path, module_type_t ty for (int j = 0; j < ast_import->select_items->count; ++j) { ast_import_select_item_t *item = ast_import->select_items->take[j]; char *local_name = item->alias ? item->alias : item->ident; - + // Check for redeclaration - if (table_exist(m->selective_import_table, local_name) || + if (table_exist(m->selective_import_table, local_name) || table_exist(m->import_table, local_name)) { ANALYZER_ASSERTF(false, "import item '%s' conflicts with existing import", local_name); } - + // Create selective import reference ast_import_select_t *select_ref = NEW(ast_import_select_t); select_ref->module_ident = ast_import->module_ident; select_ref->original_ident = item->ident; select_ref->import = ast_import; - + table_set(m->selective_import_table, local_name, select_ref); } } else if (ast_import->as && strlen(ast_import->as) > 0) { diff --git a/src/native/amd64.c b/src/native/amd64.c index ba984e52..2463aa1a 100644 --- a/src/native/amd64.c +++ b/src/native/amd64.c @@ -4,48 +4,48 @@ #include static char *asm_setcc_integer_trans[] = { - [LIR_OPCODE_SLT] = "setl", - [LIR_OPCODE_USLT] = "setb", - [LIR_OPCODE_SLE] = "setle", - [LIR_OPCODE_USLE] = "setbe", - [LIR_OPCODE_SGT] = "setg", - [LIR_OPCODE_USGT] = "seta", - [LIR_OPCODE_SGE] = "setge", - [LIR_OPCODE_USGE] = "setae", - [LIR_OPCODE_SEE] = "sete", - [LIR_OPCODE_SNE] = "setne", + [LIR_OPCODE_SLT] = "setl", + [LIR_OPCODE_USLT] = "setb", + [LIR_OPCODE_SLE] = "setle", + [LIR_OPCODE_USLE] = "setbe", + [LIR_OPCODE_SGT] = "setg", + [LIR_OPCODE_USGT] = "seta", + [LIR_OPCODE_SGE] = "setge", + [LIR_OPCODE_USGE] = "setae", + [LIR_OPCODE_SEE] = "sete", + [LIR_OPCODE_SNE] = "setne", }; static char *asm_setcc_float_trans[] = { - [LIR_OPCODE_SLT] = "setb", - [LIR_OPCODE_SLE] = "setbe", - [LIR_OPCODE_SGT] = "seta", - [LIR_OPCODE_SGE] = "setae", - [LIR_OPCODE_SEE] = "sete", - [LIR_OPCODE_SNE] = "setne", + [LIR_OPCODE_SLT] = "setb", + [LIR_OPCODE_SLE] = "setbe", + [LIR_OPCODE_SGT] = "seta", + [LIR_OPCODE_SGE] = "setae", + [LIR_OPCODE_SEE] = "sete", + [LIR_OPCODE_SNE] = "setne", }; static char *asm_bcc_integer_trans[] = { - [LIR_OPCODE_BLT] = "jl", - [LIR_OPCODE_BLE] = "jle", - [LIR_OPCODE_BGT] = "jg", - [LIR_OPCODE_BGE] = "jge", - [LIR_OPCODE_BULT] = "jb", - [LIR_OPCODE_BULE] = "jbe", - [LIR_OPCODE_BUGT] = "ja", - [LIR_OPCODE_BUGE] = "jae", - [LIR_OPCODE_BEE] = "je", - [LIR_OPCODE_BNE] = "jne", + [LIR_OPCODE_BLT] = "jl", + [LIR_OPCODE_BLE] = "jle", + [LIR_OPCODE_BGT] = "jg", + [LIR_OPCODE_BGE] = "jge", + [LIR_OPCODE_BULT] = "jb", + [LIR_OPCODE_BULE] = "jbe", + [LIR_OPCODE_BUGT] = "ja", + [LIR_OPCODE_BUGE] = "jae", + [LIR_OPCODE_BEE] = "je", + [LIR_OPCODE_BNE] = "jne", }; static char *asm_bcc_float_trans[] = { - [LIR_OPCODE_BLT] = "jb", - [LIR_OPCODE_BLE] = "jbe", - [LIR_OPCODE_BGT] = "ja", - [LIR_OPCODE_BGE] = "jae", - [LIR_OPCODE_BEE] = "je", - [LIR_OPCODE_BNE] = "jne", + [LIR_OPCODE_BLT] = "jb", + [LIR_OPCODE_BLE] = "jbe", + [LIR_OPCODE_BGT] = "ja", + [LIR_OPCODE_BGE] = "jae", + [LIR_OPCODE_BEE] = "je", + [LIR_OPCODE_BNE] = "jne", }; static slice_t *amd64_native_block(closure_t *c, basic_block_t *block); @@ -305,8 +305,8 @@ static slice_t *amd64_native_bal(closure_t *c, lir_op_t *op) { static slice_t *amd64_native_clv(closure_t *c, lir_op_t *op) { lir_operand_t *output = op->output; assert(output->assert_type == LIR_OPERAND_REG || - output->assert_type == LIR_OPERAND_STACK || - output->assert_type == LIR_OPERAND_INDIRECT_ADDR); + output->assert_type == LIR_OPERAND_STACK || + output->assert_type == LIR_OPERAND_INDIRECT_ADDR); assert(output); slice_t *operations = slice_new(); @@ -1079,14 +1079,17 @@ static slice_t *amd64_native_fn_end(closure_t *c, lir_op_t *op) { operations = amd64_native_return(c, op); } - // assist preempt label - char *preempt_ident = local_sym_with_fn(c, ".preempt"); - slice_push(operations, AMD64_INST("label", AMD64_SYMBOL(preempt_ident, true))); - slice_push(operations, AMD64_INST("call", AMD64_SYMBOL(ASSIST_PREEMPT_YIELD_IDENT, false))); + if (!c->fndef->is_fx) { + // assist preempt label + char *preempt_ident = local_sym_with_fn(c, ".preempt"); + slice_push(operations, AMD64_INST("label", AMD64_SYMBOL(preempt_ident, true))); + slice_push(operations, AMD64_INST("call", AMD64_SYMBOL(ASSIST_PREEMPT_YIELD_IDENT, false))); - char *safepoint_ident = local_sym_with_fn(c, ".sp.end"); - slice_push(operations, AMD64_INST("jmp", AMD64_SYMBOL(safepoint_ident, true))); + char *safepoint_ident = local_sym_with_fn(c, ".sp.end"); + slice_push(operations, AMD64_INST("jmp", AMD64_SYMBOL(safepoint_ident, true))); + } + return operations; } @@ -1178,75 +1181,75 @@ static slice_t *amd64_native_safepoint(closure_t *c, lir_op_t *op) { amd64_native_fn amd64_native_table[] = { - [LIR_OPCODE_CLR] = amd64_native_clr, - [LIR_OPCODE_CLV] = amd64_native_clv, - [LIR_OPCODE_NOP] = amd64_native_nop, - [LIR_OPCODE_CALL] = amd64_native_call, - [LIR_OPCODE_RT_CALL] = amd64_native_call, - [LIR_OPCODE_LABEL] = amd64_native_label, - [LIR_OPCODE_PUSH] = amd64_native_push, - [LIR_OPCODE_RETURN] = amd64_native_return, - [LIR_OPCODE_RET] = amd64_native_nop, - [LIR_OPCODE_BEE] = amd64_native_bcc, - [LIR_OPCODE_BNE] = amd64_native_bcc, - [LIR_OPCODE_BLT] = amd64_native_bcc, - [LIR_OPCODE_BLE] = amd64_native_bcc, - [LIR_OPCODE_BGT] = amd64_native_bcc, - [LIR_OPCODE_BGE] = amd64_native_bcc, - [LIR_OPCODE_BULT] = amd64_native_bcc, - [LIR_OPCODE_BULE] = amd64_native_bcc, - [LIR_OPCODE_BUGT] = amd64_native_bcc, - [LIR_OPCODE_BUGE] = amd64_native_bcc, - [LIR_OPCODE_BAL] = amd64_native_bal, - - // 类型扩展 - [LIR_OPCODE_UEXT] = amd64_native_zext, - [LIR_OPCODE_SEXT] = amd64_native_sext, - [LIR_OPCODE_TRUNC] = amd64_native_trunc, - [LIR_OPCODE_FTRUNC] = amd64_native_ftrunc, - [LIR_OPCODE_FEXT] = amd64_native_fext, - [LIR_OPCODE_FTOSI] = amd64_native_ftosi, - [LIR_OPCODE_FTOUI] = amd64_native_ftoui, - [LIR_OPCODE_SITOF] = amd64_native_sitof, - [LIR_OPCODE_UITOF] = amd64_native_uitof, - - [LIR_OPCODE_SAFEPOINT] = amd64_native_safepoint, - - // 一元运算符 - [LIR_OPCODE_NEG] = amd64_native_neg, - - // 位运算 - [LIR_OPCODE_XOR] = amd64_native_xor, - [LIR_OPCODE_NOT] = amd64_native_not, - [LIR_OPCODE_OR] = amd64_native_or, - [LIR_OPCODE_AND] = amd64_native_and, - [LIR_OPCODE_USHR] = amd64_native_shift, - [LIR_OPCODE_SSHR] = amd64_native_shift, - [LIR_OPCODE_USHL] = amd64_native_shift, - - // 算数运算 - [LIR_OPCODE_ADD] = amd64_native_add, - [LIR_OPCODE_SUB] = amd64_native_sub, - [LIR_OPCODE_UDIV] = amd64_native_div, - [LIR_OPCODE_SDIV] = amd64_native_div, - [LIR_OPCODE_MUL] = amd64_native_mul, - // 逻辑相关运算符 - [LIR_OPCODE_SGT] = amd64_native_scc, - [LIR_OPCODE_SGE] = amd64_native_scc, - [LIR_OPCODE_SLT] = amd64_native_scc, - [LIR_OPCODE_SLE] = amd64_native_scc, - [LIR_OPCODE_SEE] = amd64_native_scc, - [LIR_OPCODE_SNE] = amd64_native_scc, - - [LIR_OPCODE_USLT] = amd64_native_scc, - [LIR_OPCODE_USLE] = amd64_native_scc, - [LIR_OPCODE_USGT] = amd64_native_scc, - [LIR_OPCODE_USGE] = amd64_native_scc, - - [LIR_OPCODE_MOVE] = amd64_native_mov, - [LIR_OPCODE_LEA] = amd64_native_lea, - [LIR_OPCODE_FN_BEGIN] = amd64_native_fn_begin, - [LIR_OPCODE_FN_END] = amd64_native_fn_end, + [LIR_OPCODE_CLR] = amd64_native_clr, + [LIR_OPCODE_CLV] = amd64_native_clv, + [LIR_OPCODE_NOP] = amd64_native_nop, + [LIR_OPCODE_CALL] = amd64_native_call, + [LIR_OPCODE_RT_CALL] = amd64_native_call, + [LIR_OPCODE_LABEL] = amd64_native_label, + [LIR_OPCODE_PUSH] = amd64_native_push, + [LIR_OPCODE_RETURN] = amd64_native_return, + [LIR_OPCODE_RET] = amd64_native_nop, + [LIR_OPCODE_BEE] = amd64_native_bcc, + [LIR_OPCODE_BNE] = amd64_native_bcc, + [LIR_OPCODE_BLT] = amd64_native_bcc, + [LIR_OPCODE_BLE] = amd64_native_bcc, + [LIR_OPCODE_BGT] = amd64_native_bcc, + [LIR_OPCODE_BGE] = amd64_native_bcc, + [LIR_OPCODE_BULT] = amd64_native_bcc, + [LIR_OPCODE_BULE] = amd64_native_bcc, + [LIR_OPCODE_BUGT] = amd64_native_bcc, + [LIR_OPCODE_BUGE] = amd64_native_bcc, + [LIR_OPCODE_BAL] = amd64_native_bal, + + // 类型扩展 + [LIR_OPCODE_UEXT] = amd64_native_zext, + [LIR_OPCODE_SEXT] = amd64_native_sext, + [LIR_OPCODE_TRUNC] = amd64_native_trunc, + [LIR_OPCODE_FTRUNC] = amd64_native_ftrunc, + [LIR_OPCODE_FEXT] = amd64_native_fext, + [LIR_OPCODE_FTOSI] = amd64_native_ftosi, + [LIR_OPCODE_FTOUI] = amd64_native_ftoui, + [LIR_OPCODE_SITOF] = amd64_native_sitof, + [LIR_OPCODE_UITOF] = amd64_native_uitof, + + [LIR_OPCODE_SAFEPOINT] = amd64_native_safepoint, + + // 一元运算符 + [LIR_OPCODE_NEG] = amd64_native_neg, + + // 位运算 + [LIR_OPCODE_XOR] = amd64_native_xor, + [LIR_OPCODE_NOT] = amd64_native_not, + [LIR_OPCODE_OR] = amd64_native_or, + [LIR_OPCODE_AND] = amd64_native_and, + [LIR_OPCODE_USHR] = amd64_native_shift, + [LIR_OPCODE_SSHR] = amd64_native_shift, + [LIR_OPCODE_USHL] = amd64_native_shift, + + // 算数运算 + [LIR_OPCODE_ADD] = amd64_native_add, + [LIR_OPCODE_SUB] = amd64_native_sub, + [LIR_OPCODE_UDIV] = amd64_native_div, + [LIR_OPCODE_SDIV] = amd64_native_div, + [LIR_OPCODE_MUL] = amd64_native_mul, + // 逻辑相关运算符 + [LIR_OPCODE_SGT] = amd64_native_scc, + [LIR_OPCODE_SGE] = amd64_native_scc, + [LIR_OPCODE_SLT] = amd64_native_scc, + [LIR_OPCODE_SLE] = amd64_native_scc, + [LIR_OPCODE_SEE] = amd64_native_scc, + [LIR_OPCODE_SNE] = amd64_native_scc, + + [LIR_OPCODE_USLT] = amd64_native_scc, + [LIR_OPCODE_USLE] = amd64_native_scc, + [LIR_OPCODE_USGT] = amd64_native_scc, + [LIR_OPCODE_USGE] = amd64_native_scc, + + [LIR_OPCODE_MOVE] = amd64_native_mov, + [LIR_OPCODE_LEA] = amd64_native_lea, + [LIR_OPCODE_FN_BEGIN] = amd64_native_fn_begin, + [LIR_OPCODE_FN_END] = amd64_native_fn_end, }; slice_t *amd64_native_op(closure_t *c, lir_op_t *op) { diff --git a/src/native/arm64.c b/src/native/arm64.c index ee6bc3eb..e444d06e 100644 --- a/src/native/arm64.c +++ b/src/native/arm64.c @@ -109,7 +109,6 @@ static void arm64_gen_cmp(lir_op_t *op, slice_t *operations, arm64_asm_operand_t static arm64_asm_operand_t *convert_operand_to_free_reg(lir_op_t *op, slice_t *operations, arm64_asm_operand_t *source, lir_operand_t *operand, uint8_t size) { - bool is_int = false; bool is_uint = false; if (operand->assert_type == LIR_OPERAND_REG) { @@ -220,7 +219,8 @@ lir_operand_trans_arm64(closure_t *c, lir_op_t *op, lir_operand_t *operand, slic } // indirect 有符号偏移范围 [-256, 255], 如果超出范围,需要借助临时寄存器 x16 进行转换(此处转换不需要考虑 float 类型) - if (result && result->type == ARM64_ASM_OPERAND_INDIRECT && (result->indirect.offset < -256 || result->indirect.offset > 255)) { + if (result && result->type == ARM64_ASM_OPERAND_INDIRECT && ( + result->indirect.offset < -256 || result->indirect.offset > 255)) { // int64_t offset = result->indirect.offset * -1; arm64_asm_operand_t *offset_operand = arm64_imm_operand(op, operations, result->indirect.offset); @@ -289,8 +289,7 @@ lir_operand_trans_arm64(closure_t *c, lir_op_t *op, lir_operand_t *operand, slic lir_symbol_var_t *v = operand->value; result = ARM64_SYM(v->ident, false, 0, 0); - result->size = v->t.storage_size; - ; + result->size = v->t.storage_size;; return result; } @@ -533,7 +532,6 @@ static slice_t *arm64_native_mov(closure_t *c, lir_op_t *op) { int64_t value = imm->int_value; arm64_mov_imm(op, operations, result, value); } - } else if (op->first->assert_type == LIR_OPERAND_STACK || op->first->assert_type == LIR_OPERAND_INDIRECT_ADDR || op->first->assert_type == LIR_OPERAND_SYMBOL_VAR) { @@ -598,7 +596,8 @@ static slice_t *arm64_native_return(closure_t *c, lir_op_t *op) { } else { // 恢复栈帧 // 恢复 fp(x29) 和 lr(x30), ARM64_INDIRECT(sp, 16, 2) 2 表示 post-index 模式 - slice_push(operations, ARM64_INST(R_LDP, ARM64_REG(fp), ARM64_REG(lr), ARM64_INDIRECT(sp, c->stack_offset, 0, OWORD))); + slice_push(operations, ARM64_INST(R_LDP, ARM64_REG(fp), ARM64_REG(lr), + ARM64_INDIRECT(sp, c->stack_offset, 0, OWORD))); } arm64_asm_operand_t *offset_operand = arm64_imm_operand(op, operations, c->stack_offset + 16); @@ -652,8 +651,8 @@ static slice_t *arm64_native_bal(closure_t *c, lir_op_t *op) { static slice_t *arm64_native_clv(closure_t *c, lir_op_t *op) { lir_operand_t *output = op->output; assert(output->assert_type == LIR_OPERAND_REG || - output->assert_type == LIR_OPERAND_STACK || - output->assert_type == LIR_OPERAND_INDIRECT_ADDR); + output->assert_type == LIR_OPERAND_STACK || + output->assert_type == LIR_OPERAND_INDIRECT_ADDR); assert(output); slice_t *operations = slice_new(); @@ -728,7 +727,6 @@ static slice_t *arm64_native_div(closure_t *c, lir_op_t *op) { } else { slice_push(operations, ARM64_INST(R_UDIV, result, dividend, divisor)); } - } else { // 使用 FDIV 指令进行浮点数除法 slice_push(operations, ARM64_INST(R_FDIV, result, dividend, divisor)); @@ -1029,13 +1027,16 @@ static slice_t *arm64_native_fn_end(closure_t *c, lir_op_t *op) { operations = arm64_native_return(c, op); } - // assist preempt label - char *preempt_ident = local_sym_with_fn(c, ".preempt"); - slice_push(operations, ARM64_INST(R_LABEL, ARM64_SYM(preempt_ident, true, 0, 0))); - slice_push(operations, ARM64_INST(R_BL, ARM64_SYM(ASSIST_PREEMPT_YIELD_IDENT, false, 0, 0))); + if (!c->fndef->is_fx) { + // assist preempt label + char *preempt_ident = local_sym_with_fn(c, ".preempt"); + slice_push(operations, ARM64_INST(R_LABEL, ARM64_SYM(preempt_ident, true, 0, 0))); + slice_push(operations, ARM64_INST(R_BL, ARM64_SYM(ASSIST_PREEMPT_YIELD_IDENT, false, 0, 0))); + + char *safepoint_ident = local_sym_with_fn(c, ".sp.end"); + slice_push(operations, ARM64_INST(R_B, ARM64_SYM(safepoint_ident, true, 0, 0))); + } - char *safepoint_ident = local_sym_with_fn(c, ".sp.end"); - slice_push(operations, ARM64_INST(R_B, ARM64_SYM(safepoint_ident, true, 0, 0))); return operations; } @@ -1095,7 +1096,8 @@ static slice_t *arm64_native_fn_begin(closure_t *c, lir_op_t *op) { slice_push(operations, ARM64_INST(R_STR, ARM64_REG(lr), ARM64_INDIRECT(sp, offset + 8, 0, OWORD))); } else { // fp = x29, lr = x30 - slice_push(operations, ARM64_INST(R_STP, ARM64_REG(fp), ARM64_REG(lr), ARM64_INDIRECT(sp, offset, 0, OWORD))); // offset 限制 256 + slice_push(operations, ARM64_INST(R_STP, ARM64_REG(fp), ARM64_REG(lr), ARM64_INDIRECT(sp, offset, 0, OWORD))); + // offset 限制 256 } // 保存 callee-saved 寄存器 @@ -1230,24 +1232,26 @@ static slice_t *arm64_native_bcc(closure_t *c, lir_op_t *op) { // 比较 first 是否等于 second,如果相等就跳转到 result label arm64_asm_operand_t *first = lir_operand_trans_arm64(c, op, op->first, operations); arm64_asm_operand_t *second = lir_operand_trans_arm64(c, op, op->second, operations); - assert(second->type == ARM64_ASM_OPERAND_REG || second->type == ARM64_ASM_OPERAND_FREG || second->type == ARM64_ASM_OPERAND_IMMEDIATE); + assert( + second->type == ARM64_ASM_OPERAND_REG || second->type == ARM64_ASM_OPERAND_FREG || second->type == + ARM64_ASM_OPERAND_IMMEDIATE); arm64_asm_operand_t *result = lir_operand_trans_arm64(c, op, op->output, operations); arm64_gen_cmp(op, operations, second, first, arm64_is_integer_operand(op->first)); // 如果相等则跳转(beq)到标签 int32_t lir_to_asm_code[] = { - [LIR_OPCODE_BGE] = R_BGE, - [LIR_OPCODE_BGT] = R_BGT, - [LIR_OPCODE_BLE] = R_BLE, - [LIR_OPCODE_BLT] = R_BLT, - [LIR_OPCODE_BNE] = R_BNE, - [LIR_OPCODE_BEE] = R_BEQ, - // unsigned branch - [LIR_OPCODE_BUGE] = R_BHS, // branch if higher or same (unsigned >=) - [LIR_OPCODE_BUGT] = R_BHI, // branch if higher (unsigned >) - [LIR_OPCODE_BULE] = R_BLS, // branch if lower or same (unsigned <=) - [LIR_OPCODE_BULT] = R_BLO, // branch if lower (unsigned <) + [LIR_OPCODE_BGE] = R_BGE, + [LIR_OPCODE_BGT] = R_BGT, + [LIR_OPCODE_BLE] = R_BLE, + [LIR_OPCODE_BLT] = R_BLT, + [LIR_OPCODE_BNE] = R_BNE, + [LIR_OPCODE_BEE] = R_BEQ, + // unsigned branch + [LIR_OPCODE_BUGE] = R_BHS, // branch if higher or same (unsigned >=) + [LIR_OPCODE_BUGT] = R_BHI, // branch if higher (unsigned >) + [LIR_OPCODE_BULE] = R_BLS, // branch if lower or same (unsigned <=) + [LIR_OPCODE_BULT] = R_BLO, // branch if lower (unsigned <) }; int32_t asm_code = lir_to_asm_code[op->code]; @@ -1260,84 +1264,84 @@ static slice_t *arm64_native_bcc(closure_t *c, lir_op_t *op) { arm64_native_fn arm64_native_table[] = { - [LIR_OPCODE_CLR] = arm64_native_clr, - [LIR_OPCODE_CLV] = arm64_native_clv, - [LIR_OPCODE_NOP] = arm64_native_nop, - [LIR_OPCODE_CALL] = arm64_native_call, - [LIR_OPCODE_RT_CALL] = arm64_native_call, - [LIR_OPCODE_LABEL] = arm64_native_label, - [LIR_OPCODE_PUSH] = arm64_native_push, - [LIR_OPCODE_RETURN] = arm64_native_return, - [LIR_OPCODE_RET] = arm64_native_nop, - [LIR_OPCODE_BAL] = arm64_native_bal, - - [LIR_OPCODE_BEE] = arm64_native_bcc, - [LIR_OPCODE_BNE] = arm64_native_bcc, - [LIR_OPCODE_BGE] = arm64_native_bcc, - [LIR_OPCODE_BGT] = arm64_native_bcc, - [LIR_OPCODE_BLE] = arm64_native_bcc, - [LIR_OPCODE_BLT] = arm64_native_bcc, - [LIR_OPCODE_BUGE] = arm64_native_bcc, - [LIR_OPCODE_BUGT] = arm64_native_bcc, - [LIR_OPCODE_BULE] = arm64_native_bcc, - [LIR_OPCODE_BULT] = arm64_native_bcc, - - // 一元运算符 - [LIR_OPCODE_NEG] = arm64_native_neg, - - // 位运算 - [LIR_OPCODE_XOR] = arm64_native_xor, - [LIR_OPCODE_NOT] = arm64_native_not, - [LIR_OPCODE_OR] = arm64_native_or, - [LIR_OPCODE_AND] = arm64_native_and, - [LIR_OPCODE_SSHR] = arm64_native_shift, - [LIR_OPCODE_USHL] = arm64_native_shift, - [LIR_OPCODE_USHR] = arm64_native_shift, - - // 算数运算 - [LIR_OPCODE_ADD] = arm64_native_add, - [LIR_OPCODE_SUB] = arm64_native_sub, - [LIR_OPCODE_UDIV] = arm64_native_div, - [LIR_OPCODE_SDIV] = arm64_native_div, - [LIR_OPCODE_MUL] = arm64_native_mul, - [LIR_OPCODE_UREM] = arm64_native_rem, - [LIR_OPCODE_SREM] = arm64_native_rem, - - // FMA (Fused Multiply-Add/Subtract) - [ARM64_OPCODE_MADD] = arm64_native_fma, - [ARM64_OPCODE_MSUB] = arm64_native_fma, - [ARM64_OPCODE_FMADD] = arm64_native_fma, - [ARM64_OPCODE_FMSUB] = arm64_native_fma, - [ARM64_OPCODE_FNMSUB] = arm64_native_fma, - - // 逻辑相关运算符 - [LIR_OPCODE_SGT] = arm64_native_scc, - [LIR_OPCODE_SGE] = arm64_native_scc, - [LIR_OPCODE_SLT] = arm64_native_scc, - [LIR_OPCODE_USLT] = arm64_native_scc, - [LIR_OPCODE_SLE] = arm64_native_scc, - [LIR_OPCODE_USLE] = arm64_native_scc, - [LIR_OPCODE_USGT] = arm64_native_scc, - [LIR_OPCODE_USGE] = arm64_native_scc, - [LIR_OPCODE_SEE] = arm64_native_scc, - [LIR_OPCODE_SNE] = arm64_native_scc, - - [LIR_OPCODE_MOVE] = arm64_native_mov, - [LIR_OPCODE_LEA] = arm64_native_lea, - [LIR_OPCODE_UEXT] = arm64_native_uext, - [LIR_OPCODE_SEXT] = arm64_native_sext, - [LIR_OPCODE_TRUNC] = arm64_native_trunc, - [LIR_OPCODE_FTRUNC] = arm64_native_ftrunc, - [LIR_OPCODE_FEXT] = arm64_native_fext, - [LIR_OPCODE_FTOSI] = arm64_native_ftosi, - [LIR_OPCODE_FTOUI] = arm64_native_ftoui, - [LIR_OPCODE_SITOF] = arm64_native_sitof, - [LIR_OPCODE_UITOF] = arm64_native_uitof, - - [LIR_OPCODE_FN_BEGIN] = arm64_native_fn_begin, - [LIR_OPCODE_FN_END] = arm64_native_fn_end, - - [LIR_OPCODE_SAFEPOINT] = arm64_native_safepoint, + [LIR_OPCODE_CLR] = arm64_native_clr, + [LIR_OPCODE_CLV] = arm64_native_clv, + [LIR_OPCODE_NOP] = arm64_native_nop, + [LIR_OPCODE_CALL] = arm64_native_call, + [LIR_OPCODE_RT_CALL] = arm64_native_call, + [LIR_OPCODE_LABEL] = arm64_native_label, + [LIR_OPCODE_PUSH] = arm64_native_push, + [LIR_OPCODE_RETURN] = arm64_native_return, + [LIR_OPCODE_RET] = arm64_native_nop, + [LIR_OPCODE_BAL] = arm64_native_bal, + + [LIR_OPCODE_BEE] = arm64_native_bcc, + [LIR_OPCODE_BNE] = arm64_native_bcc, + [LIR_OPCODE_BGE] = arm64_native_bcc, + [LIR_OPCODE_BGT] = arm64_native_bcc, + [LIR_OPCODE_BLE] = arm64_native_bcc, + [LIR_OPCODE_BLT] = arm64_native_bcc, + [LIR_OPCODE_BUGE] = arm64_native_bcc, + [LIR_OPCODE_BUGT] = arm64_native_bcc, + [LIR_OPCODE_BULE] = arm64_native_bcc, + [LIR_OPCODE_BULT] = arm64_native_bcc, + + // 一元运算符 + [LIR_OPCODE_NEG] = arm64_native_neg, + + // 位运算 + [LIR_OPCODE_XOR] = arm64_native_xor, + [LIR_OPCODE_NOT] = arm64_native_not, + [LIR_OPCODE_OR] = arm64_native_or, + [LIR_OPCODE_AND] = arm64_native_and, + [LIR_OPCODE_SSHR] = arm64_native_shift, + [LIR_OPCODE_USHL] = arm64_native_shift, + [LIR_OPCODE_USHR] = arm64_native_shift, + + // 算数运算 + [LIR_OPCODE_ADD] = arm64_native_add, + [LIR_OPCODE_SUB] = arm64_native_sub, + [LIR_OPCODE_UDIV] = arm64_native_div, + [LIR_OPCODE_SDIV] = arm64_native_div, + [LIR_OPCODE_MUL] = arm64_native_mul, + [LIR_OPCODE_UREM] = arm64_native_rem, + [LIR_OPCODE_SREM] = arm64_native_rem, + + // FMA (Fused Multiply-Add/Subtract) + [ARM64_OPCODE_MADD] = arm64_native_fma, + [ARM64_OPCODE_MSUB] = arm64_native_fma, + [ARM64_OPCODE_FMADD] = arm64_native_fma, + [ARM64_OPCODE_FMSUB] = arm64_native_fma, + [ARM64_OPCODE_FNMSUB] = arm64_native_fma, + + // 逻辑相关运算符 + [LIR_OPCODE_SGT] = arm64_native_scc, + [LIR_OPCODE_SGE] = arm64_native_scc, + [LIR_OPCODE_SLT] = arm64_native_scc, + [LIR_OPCODE_USLT] = arm64_native_scc, + [LIR_OPCODE_SLE] = arm64_native_scc, + [LIR_OPCODE_USLE] = arm64_native_scc, + [LIR_OPCODE_USGT] = arm64_native_scc, + [LIR_OPCODE_USGE] = arm64_native_scc, + [LIR_OPCODE_SEE] = arm64_native_scc, + [LIR_OPCODE_SNE] = arm64_native_scc, + + [LIR_OPCODE_MOVE] = arm64_native_mov, + [LIR_OPCODE_LEA] = arm64_native_lea, + [LIR_OPCODE_UEXT] = arm64_native_uext, + [LIR_OPCODE_SEXT] = arm64_native_sext, + [LIR_OPCODE_TRUNC] = arm64_native_trunc, + [LIR_OPCODE_FTRUNC] = arm64_native_ftrunc, + [LIR_OPCODE_FEXT] = arm64_native_fext, + [LIR_OPCODE_FTOSI] = arm64_native_ftosi, + [LIR_OPCODE_FTOUI] = arm64_native_ftoui, + [LIR_OPCODE_SITOF] = arm64_native_sitof, + [LIR_OPCODE_UITOF] = arm64_native_uitof, + + [LIR_OPCODE_FN_BEGIN] = arm64_native_fn_begin, + [LIR_OPCODE_FN_END] = arm64_native_fn_end, + + [LIR_OPCODE_SAFEPOINT] = arm64_native_safepoint, }; diff --git a/src/rtype.h b/src/rtype.h index c8312214..e8061a6d 100644 --- a/src/rtype.h +++ b/src/rtype.h @@ -99,7 +99,7 @@ static inline int64_t type_hash(type_t t) { } if (t.kind == TYPE_FN) { - char *str = dsprintf("fn.%ld", type_hash(t.fn->return_type)); + char *str = dsprintf("%s.%ld", t.fn->is_fx ? "fx" : "fn", type_hash(t.fn->return_type)); for (int i = 0; i < t.fn->param_types->length; ++i) { type_t *param_type = ct_list_value(t.fn->param_types, i); str = str_connect(str, dsprintf(".%ld", type_hash(*param_type))); diff --git a/src/semantic/analyzer.c b/src/semantic/analyzer.c index 664a7649..c93fdac7 100644 --- a/src/semantic/analyzer.c +++ b/src/semantic/analyzer.c @@ -190,6 +190,7 @@ static type_t analyzer_type_fn(ast_fndef_t *fndef) { } f->is_rest = fndef->rest_param; f->is_errable = fndef->is_errable; + f->is_fx = fndef->is_fx; type_t result = type_new(TYPE_FN, f); result.status = REDUCTION_STATUS_UNDO; @@ -1042,8 +1043,7 @@ static void analyzer_global_fndef(module_t *m, ast_fndef_t *fndef) { } fndef->params = params; - // builtin type 没有注册在符号表, 所以也不能添加 type impl method - if (!is_impl_builtin_type(fndef->impl_type.kind)) { + if (!is_impl_builtin_type(fndef->impl_type.kind) && fndef->self_kind != PARAM_SELF_NULL) { symbol_typedef_add_method(fndef->impl_type.ident, fndef->symbol_name, fndef); } } @@ -1927,8 +1927,13 @@ static void analyzer_for_tradition(module_t *m, ast_for_tradition_stmt_t *stmt) } static void analyzer_for_iterator(module_t *m, ast_for_iterator_stmt_t *stmt) { - // iterate 是对变量的使用,所以其在 scope - analyzer_expr(m, &stmt->iterate); + if (stmt->is_range) { + analyzer_expr(m, &stmt->range_start); + analyzer_expr(m, &stmt->range_end); + } else { + // iterate 是对变量的使用,所以其在 scope + analyzer_expr(m, &stmt->iterate); + } analyzer_begin_scope(m); // iterator 中创建的 key 和 value 的所在作用域都应该在当前 for scope 里面 @@ -1947,6 +1952,14 @@ static void analyzer_return(module_t *m, ast_return_stmt_t *stmt) { } } +static void analyzer_defer(module_t *m, ast_defer_stmt_t *stmt) { + m->in_defer_block_depth++; + analyzer_begin_scope(m); + analyzer_body(m, stmt->body); + analyzer_end_scope(m); + m->in_defer_block_depth--; +} + // type foo = int static void analyzer_typedef_stmt(module_t *m, ast_typedef_stmt_t *stmt) { // local type alias 不允许携带 param @@ -2168,6 +2181,16 @@ static void analyzer_stmt(module_t *m, ast_stmt_t *stmt) { m->current_line = stmt->line; m->current_column = stmt->column; + if (m->in_defer_block_depth > 0) { + if (stmt->assert_type == AST_STMT_RETURN || + stmt->assert_type == AST_STMT_BREAK || + stmt->assert_type == AST_STMT_CONTINUE || + stmt->assert_type == AST_STMT_THROW || + stmt->assert_type == AST_STMT_RET) { + ANALYZER_ASSERTF(false, "return/break/continue/throw/ret are not allowed inside defer block"); + } + } + switch (stmt->assert_type) { case AST_STMT_RET: case AST_STMT_EXPR_FAKE: { @@ -2222,6 +2245,9 @@ static void analyzer_stmt(module_t *m, ast_stmt_t *stmt) { case AST_STMT_RETURN: { return analyzer_return(m, stmt->value); } + case AST_STMT_DEFER: { + return analyzer_defer(m, stmt->value); + } case AST_STMT_TYPEDEF: { return analyzer_typedef_stmt(m, stmt->value); } diff --git a/src/semantic/generics.c b/src/semantic/generics.c index 4f72e0ed..fac2133c 100644 --- a/src/semantic/generics.c +++ b/src/semantic/generics.c @@ -217,9 +217,9 @@ static bool constraint_has_interface(module_t *m, ast_generics_param_t *param, c /** * 检查约束接口中是否声明了指定的方法名 */ -static bool constraint_has_method(module_t *m, ast_generics_param_t *param, char *method_name) { +static type_fn_t *constraint_find_method(module_t *m, ast_generics_param_t *param, char *method_name) { if (!param || param->constraints.elements->length == 0) { - return false; + return NULL; } for (int i = 0; i < param->constraints.elements->length; i++) { @@ -234,12 +234,12 @@ static bool constraint_has_method(module_t *m, ast_generics_param_t *param, char type_t *element = ct_list_value(interface_type->elements, j); if (element->kind == TYPE_FN && element->fn && element->fn->fn_name && str_equal(element->fn->fn_name, method_name)) { - return true; + return element->fn; } } } - return false; + return NULL; } static ast_generics_param_t *expr_generics_param(module_t *m, ast_expr_t *expr) { @@ -455,9 +455,19 @@ static void generics_call(module_t *m, ast_call_t *call) { } // 检查约束接口中是否声明了该方法 - bool found = constraint_has_method(m, param, select->key); - GENERIC_ASSERTF(found, "generic param '%s' has no constraint declaring fn '%s'", + type_fn_t *found_method = constraint_find_method(m, param, select->key); + GENERIC_ASSERTF(found_method, "generic param '%s' has no constraint declaring fn '%s'", generic_param_ident, select->key); + + // 检查泛型参数数量是否匹配 + if (found_method) { + int call_generics_count = call->generics_args ? call->generics_args->length : 0; + bool method_is_generic = found_method->is_tpl; + if (!method_is_generic && call_generics_count > 0) { + GENERIC_ASSERTF(false, "method '%s' has no generic parameters, but %d generic args provided", + select->key, call_generics_count); + } + } } /** @@ -582,7 +592,12 @@ static void generics_stmt(module_t *m, ast_stmt_t *stmt) { } case AST_STMT_FOR_ITERATOR: { ast_for_iterator_stmt_t *for_iter = stmt->value; - generics_expr(m, &for_iter->iterate); + if (for_iter->is_range) { + generics_expr(m, &for_iter->range_start); + generics_expr(m, &for_iter->range_end); + } else { + generics_expr(m, &for_iter->iterate); + } generics_body(m, for_iter->body); break; } @@ -612,6 +627,11 @@ static void generics_stmt(module_t *m, ast_stmt_t *stmt) { generics_expr(m, &throw_stmt->error); break; } + case AST_STMT_DEFER: { + ast_defer_stmt_t *defer_stmt = stmt->value; + generics_body(m, defer_stmt->body); + break; + } case AST_CATCH: { ast_catch_t *catch_stmt = stmt->value; generics_expr(m, &catch_stmt->try_expr); diff --git a/src/semantic/infer.c b/src/semantic/infer.c index e2354294..c2cb1c6f 100644 --- a/src/semantic/infer.c +++ b/src/semantic/infer.c @@ -1,21 +1,18 @@ #include "infer.h" #include "generics.h" +#include "interface.h" #include #include "analyzer.h" +#include "src/astgen.h" #include "src/debug/debug.h" #include "src/error.h" -static void -check_typedef_impl(module_t *m, type_t *impl_interface, char *typedef_ident, ast_typedef_stmt_t *typedef_stmt); - static type_t reduction_type_visited(module_t *m, type_t t, struct sc_map_s64 *visited); static type_t reduction_type_ident(module_t *m, type_t t, struct sc_map_s64 *visited); -static type_t type_param_special(module_t *m, type_t t, table_t *arg_table, struct sc_map_s64 *visited); - static type_fn_t *infer_call_left(module_t *m, ast_call_t *call, type_t target_type); static list_t *infer_struct_properties(module_t *m, type_struct_t *type_struct, list_t *properties); @@ -76,41 +73,6 @@ bool generics_constraints_compare(ast_generics_constraints *left, ast_generics_c return true; } -/** - * 递归查找 stmt 中是否包含 target_interface - */ -static bool check_impl_interface_contains(module_t *m, ast_typedef_stmt_t *stmt, type_t *find_target_interface) { - if (!stmt->impl_interfaces) { - return false; - } - - for (int i = 0; i < stmt->impl_interfaces->length; ++i) { - type_t *impl_interface = ct_list_value(stmt->impl_interfaces, i); - if (str_equal(impl_interface->ident, find_target_interface->ident)) { - return true; - } - - symbol_t *s = symbol_table_get(impl_interface->ident); - if (!s) { - continue; - } - - assert(s && s->type == SYMBOL_TYPE); - ast_typedef_stmt_t *typedef_stmt = s->ast_value; - if (typedef_stmt->impl_interfaces == NULL) { - continue; - } - - if (check_impl_interface_contains(m, typedef_stmt, find_target_interface)) { - return true; - } - - // continue - } - - return false; -} - static bool interface_alloc_types_contains(module_t *m, type_interface_t *interface_type, type_t src) { if (!interface_type || !interface_type->alloc_types || interface_type->alloc_types->length == 0) { return false; @@ -134,6 +96,10 @@ static bool interface_alloc_types_contains(module_t *m, type_interface_t *interf } static void generics_constraints_check(module_t *m, ast_generics_constraints *constraints, type_t *src) { + if (constraints->elements->length == 0) { + return; + } + // 对 constraints 进行类型还原 for (int j = 0; j < constraints->elements->length; ++j) { type_t *constraint = ct_list_value(constraints->elements, j); @@ -142,10 +108,6 @@ static void generics_constraints_check(module_t *m, ast_generics_constraints *co "generic constraints only support interface '&' constraints"); } - if (constraints->elements->length == 0) { - return; - } - for (int i = 0; i < constraints->elements->length; ++i) { type_t *expect_interface_type = ct_list_value(constraints->elements, i); assert(expect_interface_type->ident_kind == TYPE_IDENT_INTERFACE); @@ -176,7 +138,6 @@ static void generics_constraints_check(module_t *m, ast_generics_constraints *co assert(temp_target_type.ident); - symbol_t *s = symbol_table_get(temp_target_type.ident); if (!s) { // maybe builtin type @@ -196,23 +157,6 @@ static void generics_constraints_check(module_t *m, ast_generics_constraints *co // 禁止鸭子类型 INFER_ASSERTF(found, "type '%s' not impl '%s' interface", temp_target_type.ident, expect_interface_type->ident); - check_typedef_impl(m, expect_interface_type, temp_target_type.ident, typedef_stmt); - } -} - -static void impl_generics_constraints_check(module_t *m, ast_fndef_t *fndef, list_t *impl_gen_args) { - if (!fndef || !fndef->generics_params || !impl_gen_args) { - return; - } - - INFER_ASSERTF(fndef->generics_params->length == impl_gen_args->length, "type '%s' param not match", - fndef->impl_type.ident); - - for (int i = 0; i < fndef->generics_params->length; ++i) { - ast_generics_param_t *param = ct_list_value(fndef->generics_params, i); - type_t *arg_type = ct_list_value(impl_gen_args, i); - type_t temp_arg = reduction_type(m, *arg_type); - generics_constraints_check(m, ¶m->constraints, &temp_arg); } } @@ -432,6 +376,10 @@ bool type_generics(type_t dst, type_t src, table_t *generics_param_table) { return false; } + if (left_type_fn->is_fx != right_type_fn->is_fx) { + return false; + } + for (int i = 0; i < left_type_fn->param_types->length; ++i) { type_t *left_formal_type = ct_list_value(left_type_fn->param_types, i); type_t *right_formal_type = ct_list_value(right_type_fn->param_types, i); @@ -517,8 +465,6 @@ static bool type_compare_ident_args_visited(list_t *dst_args, list_t *src_args, * @return */ bool type_compare_visited(type_t dst, type_t src, table_t *visited) { - assert(!ident_is_generics_param(&dst)); - assert(!ident_is_generics_param(&src)); assertf(dst.status == REDUCTION_STATUS_DONE, "type '%s' not reduction", type_format(dst)); assertf(src.status == REDUCTION_STATUS_DONE, "type '%s' not reduction", type_format(src)); assertf(dst.kind != TYPE_UNKNOWN && src.kind != TYPE_UNKNOWN, "type unknown cannot infer"); @@ -590,6 +536,14 @@ bool type_compare_visited(type_t dst, type_t src, table_t *visited) { return false; } + if (ident_is_generics_param(&dst)) { + if (!ident_is_generics_param(&src)) { + return false; + } + + return str_equal(dst.ident, src.ident); + } + // any 可以批判任何类型,即使右值是 any 或者 union,union 需要经过特殊的 union_to_any 转换 if (dst.kind == TYPE_ANY) { return true; @@ -710,6 +664,10 @@ bool type_compare_visited(type_t dst, type_t src, table_t *visited) { return false; } + if (left_type_fn->is_fx != right_type_fn->is_fx) { + return false; + } + for (int i = 0; i < left_type_fn->param_types->length; ++i) { type_t *left_formal_type = ct_list_value(left_type_fn->param_types, i); type_t *right_formal_type = ct_list_value(right_type_fn->param_types, i); @@ -784,9 +742,12 @@ static table_t *generics_args_table(module_t *m, ast_fndef_t *temp_fn, ast_call_ ct_stack_t *stash_stack = m->infer_type_args_stack; m->infer_type_args_stack = NULL; + // skip formal self param int formal_param_offset = 0; - // impl 方法调用在 generics 特化阶段尚未注入 self 参数 - if (temp_fn->is_impl && !temp_fn->is_static && temp_fn->self_kind != PARAM_SELF_NULL) { + if (temp_fn->is_impl && + !temp_fn->is_static && + temp_fn->self_kind != PARAM_SELF_NULL && + !call->inject_self_arg) { formal_param_offset = 1; } @@ -796,7 +757,6 @@ static table_t *generics_args_table(module_t *m, ast_fndef_t *temp_fn, ast_call_ ast_expr_t *arg = ct_list_value(call->args, i); type_t arg_type = infer_right_expr(m, arg, type_kind_new(TYPE_UNKNOWN)); - // 形参 type reduction type_t *formal_type = select_generics_fn_param(temp_fn, i + formal_param_offset, is_spread); INFER_ASSERTF(formal_type, "too many arguments"); @@ -831,6 +791,8 @@ static table_t *generics_args_table(module_t *m, ast_fndef_t *temp_fn, ast_call_ INFER_ASSERTF(table_exist(args_table, param->ident), "cannot infer generics param '%s'", param->ident); type_t *arg_type = table_get(args_table, param->ident); + + // TODO 这里只需要判断 contains generics_constraints_check(m, ¶m->constraints, arg_type); } @@ -1214,7 +1176,6 @@ static type_t infer_as_expr(module_t *m, ast_expr_t *expr) { bool found = check_impl_interface_contains(m, typedef_stmt, &src_type); // 禁止鸭子类型 INFER_ASSERTF(found, "type '%s' not impl '%s' interface", src_type.ident, src_type.ident); - check_typedef_impl(m, &src_type, temp_target_type.ident, typedef_stmt); return target_type; } @@ -2407,6 +2368,10 @@ static ast_fndef_t *generics_special_fn(module_t *m, ast_call_t *call, type_t ta // rewrite special fn special_fn->symbol_name = symbol_name; + if (special_fn->receiver_wrapper_ident) { + special_fn->receiver_wrapper_ident = str_connect_by(special_fn->receiver_wrapper_ident, args_hash, + GEN_REWRITE_SEPARATOR); + } // 注册到全局符号表(还未基于 args_hash infer + reduction) assert(!special_fn->is_local); @@ -2769,6 +2734,7 @@ static type_fn_t *infer_impl_call_rewrite(module_t *m, ast_call_t *call, type_t list_t *args = ct_list_new(sizeof(ast_expr_t)); if (left_type.fn->self_kind != PARAM_SELF_NULL) { ct_list_push(args, self_arg_rewrite(m, left_type.fn, self_arg)); + call->inject_self_arg = true; } for (int i = 0; i < call->args->length; ++i) { @@ -2848,6 +2814,11 @@ static type_t infer_call(module_t *m, ast_call_t *call, type_t target_type, bool call->return_type = type_fn->return_type; + if (m->current_fn && m->current_fn->is_fx && !type_fn->is_fx) { + INFER_ASSERTF(false, "calling fn `%s` from fx `%s` is not allowed.", + type_fn->fn_name ? type_fn->fn_name : "lambda", m->current_fn->fn_name); + } + // catch 语句中可以包含多条 call 语句, 都统一处理了 if (type_fn->is_errable && check_errable) { INFER_ASSERTF(m->current_fn->is_errable || m->be_caught > 0, @@ -3083,6 +3054,19 @@ static void infer_for_cond_stmt(module_t *m, ast_for_cond_stmt_t *stmt) { infer_body(m, stmt->body); } +static void infer_for_iterator_range_rewrite(module_t *m, ast_stmt_t *stmt) { + ast_for_iterator_stmt_t *for_iter = stmt->value; + INFER_ASSERTF(for_iter->second == NULL, "for range only supports one iterator variable"); + + type_t range_end_type = infer_right_expr(m, ast_expr_copy(m, &for_iter->range_end), type_kind_new(TYPE_UNKNOWN)); + INFER_ASSERTF(is_integer(range_end_type.kind), + "for range end type must be integer, actual=%s", type_format(range_end_type)); + for_iter->first.type = range_end_type; + + stmt->assert_type = AST_STMT_FOR_TRADITION; + stmt->value = astgen_for_range_rewrite(for_iter); +} + /** * 仅 list 和 map 类型支持 iterate * @param stmt @@ -3180,6 +3164,10 @@ static void infer_return(module_t *m, ast_return_stmt_t *stmt) { } } +static void infer_defer(module_t *m, ast_defer_stmt_t *stmt) { + infer_body(m, stmt->body); +} + static void infer_ret(module_t *m, ast_ret_stmt_t *stmt) { type_t *target_type = stack_top(m->current_fn->ret_target_types); assert(target_type); @@ -3404,7 +3392,12 @@ static void infer_stmt(module_t *m, ast_stmt_t *stmt) { return infer_for_cond_stmt(m, stmt->value); } case AST_STMT_FOR_ITERATOR: { - return infer_for_iterator(m, stmt->value); + ast_for_iterator_stmt_t *for_iter = stmt->value; + if (for_iter->is_range) { + infer_for_iterator_range_rewrite(m, stmt); + return infer_for_tradition(m, stmt->value); + } + return infer_for_iterator(m, for_iter); } case AST_STMT_FOR_TRADITION: { return infer_for_tradition(m, stmt->value); @@ -3415,6 +3408,9 @@ static void infer_stmt(module_t *m, ast_stmt_t *stmt) { case AST_STMT_RETURN: { return infer_return(m, stmt->value); } + case AST_STMT_DEFER: { + return infer_defer(m, stmt->value); + } case AST_STMT_RET: { return infer_ret(m, stmt->value); } @@ -3625,6 +3621,22 @@ static ast_expr_t as_to_interface(module_t *m, ast_expr_t *expr, type_t interfac assert(expr->type.status == REDUCTION_STATUS_DONE); assert(interface_type.status == REDUCTION_STATUS_DONE); + // object safety check: interface with generic methods cannot be used as fat pointer (dynamic dispatch) + // generic method interfaces can only be used as static generic constraints, e.g. fn foo(A a) + type_interface_t *iface = interface_type.interface; + if (iface && iface->elements) { + for (int i = 0; i < iface->elements->length; ++i) { + type_t *element = ct_list_value(iface->elements, i); + if (element->kind == TYPE_FN && element->fn && element->fn->is_tpl) { + INFER_ASSERTF(false, + "interface '%s' contains generic method '%s', " + "cannot be used as dynamic dispatch.", + interface_type.ident, + element->fn->fn_name); + } + } + } + // auto destr ptr type_t src_type = expr->type; if (expr->type.kind == TYPE_REF || expr->type.kind == TYPE_PTR) { @@ -3642,9 +3654,7 @@ static ast_expr_t as_to_interface(module_t *m, ast_expr_t *expr, type_t interfac // check actual_type impl 是否包含 target_type.ident bool found = check_impl_interface_contains(m, typedef_stmt, &interface_type); // 禁止鸭子类型 - INFER_ASSERTF(found, "type '%s' not impl '%s' interface", src_type.ident, interface_type.ident); - - check_typedef_impl(m, &interface_type, src_type.ident, typedef_stmt); + INFER_ASSERTF(found, "type '%s' not impl '%s' interface", type_format(src_type), type_format(interface_type)); // auto as to interface, expr as interface_union, will handle in linear return ast_type_as(*expr, interface_type); @@ -3852,267 +3862,17 @@ static type_t reduction_complex_type(module_t *m, type_t t, struct sc_map_s64 *v exit(1); } -static type_t type_param_special(module_t *m, type_t t, table_t *arg_table, struct sc_map_s64 *visited) { - assert(t.kind == TYPE_IDENT); - assert(t.ident_kind == TYPE_IDENT_GENERICS_PARAM); - - // 实参可以没有 reduction - type_t *arg_type = table_get(arg_table, t.ident); - return reduction_type_visited(m, *arg_type, visited); -} - -/** - * 为值类型接收器生成包装函数 - * 当 self_kind == PARAM_SELF_T 时,interface 存储指针数据但方法期望值类型 - * wrapper 接收指针参数,解引用后调用原函数 - * - * 原函数: fn dog.speak(self) { ... } - * 生成的 wrapper: fn dog.speak_receiver_wrapper(*dog ptr) { return dog.speak(*ptr) } - */ -static ast_fndef_t *generate_receiver_wrapper(module_t *m, ast_fndef_t *origin_fndef, type_t impl_type) { - // 创建 wrapper 函数定义 - ast_fndef_t *wrapper = ast_fndef_new(m, origin_fndef->line, origin_fndef->column); - - // 设置函数名称和符号名 - wrapper->fn_name = dsprintf("%s_receiver_wrapper", origin_fndef->fn_name); - wrapper->symbol_name = dsprintf("%s_receiver_wrapper", origin_fndef->symbol_name); - wrapper->fn_name_with_pkg = dsprintf("%s_receiver_wrapper", origin_fndef->fn_name_with_pkg); - - // 复制返回类型和其他属性 - wrapper->return_type = origin_fndef->return_type; - wrapper->is_errable = origin_fndef->is_errable; - wrapper->is_impl = true; - wrapper->impl_type = impl_type; - wrapper->self_kind = PARAM_SELF_REF_T; // wrapper 接收指针参数 - - // 创建参数列表 - 第一个参数是 ref - wrapper->params = ct_list_new(sizeof(ast_var_decl_t)); - - // 为 self 参数生成唯一标识符并注册到符号表 - char *self_unique_ident = var_unique_ident(m, FN_SELF_NAME); - ast_var_decl_t *self_param = NEW(ast_var_decl_t); - self_param->ident = self_unique_ident; - self_param->type = type_refof(impl_type); - symbol_table_set(self_unique_ident, SYMBOL_VAR, self_param, true); - ct_list_push(wrapper->params, self_param); - - // 复制原函数的其他参数(跳过第一个 self 参数) - for (int i = 1; i < origin_fndef->params->length; ++i) { - ast_var_decl_t *param = ct_list_value(origin_fndef->params, i); - ct_list_push(wrapper->params, param); - } - - // 构建函数体:return origin_fn(*self, other_args...) - wrapper->body = slice_new(); - - // 创建解引用表达式: *self (使用唯一标识符) - ast_unary_expr_t *deref_expr = NEW(ast_unary_expr_t); - deref_expr->op = AST_OP_IA; // indirect address (dereference) - deref_expr->operand = (ast_expr_t){ - .assert_type = AST_EXPR_IDENT, - .value = ast_new_ident(self_unique_ident), - .line = origin_fndef->line, - .column = origin_fndef->column, - }; - - // 创建 call 表达式 - ast_call_t *call = NEW(ast_call_t); - call->left = (ast_expr_t){ - .assert_type = AST_EXPR_IDENT, - .value = ast_new_ident(origin_fndef->symbol_name), - .line = origin_fndef->line, - .column = origin_fndef->column, - }; - call->args = ct_list_new(sizeof(ast_expr_t)); - call->generics_args = NULL; - call->spread = false; - - // 第一个参数是解引用的 self - ast_expr_t deref_arg = { - .assert_type = AST_EXPR_UNARY, - .value = deref_expr, - .line = origin_fndef->line, - .column = origin_fndef->column, - }; - ct_list_push(call->args, &deref_arg); - - // 添加其他参数 - for (int i = 1; i < origin_fndef->params->length; ++i) { - ast_var_decl_t *param = ct_list_value(origin_fndef->params, i); - ast_expr_t arg = { - .assert_type = AST_EXPR_IDENT, - .value = ast_new_ident(param->ident), - .line = origin_fndef->line, - .column = origin_fndef->column, - }; - ct_list_push(call->args, &arg); - } - - // 创建 return 语句 - ast_return_stmt_t *ret_stmt = NEW(ast_return_stmt_t); - if (origin_fndef->return_type.kind != TYPE_VOID) { - ret_stmt->expr = NEW(ast_expr_t); - ret_stmt->expr->assert_type = AST_CALL; - ret_stmt->expr->value = call; - ret_stmt->expr->line = origin_fndef->line; - ret_stmt->expr->column = origin_fndef->column; - } else { - // void 返回类型,只调用不 return - ret_stmt->expr = NULL; - } - - ast_stmt_t *stmt = NEW(ast_stmt_t); - if (origin_fndef->return_type.kind != TYPE_VOID) { - stmt->assert_type = AST_STMT_RETURN; - stmt->value = ret_stmt; - } else { - // void 返回类型,改为表达式语句 - stmt->assert_type = AST_CALL; - stmt->value = call; - } - stmt->line = origin_fndef->line; - stmt->column = origin_fndef->column; - slice_push(wrapper->body, stmt); - - return wrapper; -} - -static void -check_typedef_impl(module_t *m, type_t *impl_interface, char *typedef_ident, ast_typedef_stmt_t *typedef_stmt) { - assert(impl_interface->ident_kind == TYPE_IDENT_INTERFACE); - assert(impl_interface->status == REDUCTION_STATUS_DONE); - assert(impl_interface->kind == TYPE_INTERFACE); - type_interface_t *interface_type = impl_interface->interface; - if (typedef_stmt->is_interface) { - for (int i = 0; i < typedef_stmt->impl_interfaces->length; ++i) { - type_t *actual_impl_interface = ct_list_value(typedef_stmt->impl_interfaces, i); - if (str_equal(actual_impl_interface->ident, impl_interface->ident)) { - return; - } - } - INFER_ASSERTF(false, "interface '%s' impl not contains '%s'", typedef_stmt->ident, impl_interface->ident); - } - - // check impl - for (int j = 0; j < interface_type->elements->length; ++j) { - type_t *expect_type = ct_list_value(interface_type->elements, j); - assert(expect_type->status == REDUCTION_STATUS_DONE); - assert(expect_type->kind == TYPE_FN); - type_fn_t *interface_fn_type = expect_type->fn; - assert(interface_fn_type->fn_name); - - // find fn from symbol table - char *fn_ident = str_connect_by(typedef_ident, interface_fn_type->fn_name, IMPL_CONNECT_IDENT); - - // find ast_fn by teypdef_stmt.sc_map - ast_fndef_t *ast_fndef = sc_map_get_sv(&typedef_stmt->method_table, fn_ident); - - INFER_ASSERTF(ast_fndef, "type '%s' not impl fn '%s' for interface '%s'", - typedef_ident, - interface_fn_type->fn_name, - impl_interface->ident); - - // 当 self_kind == PARAM_SELF_T 时,生成 receiver_wrapper - // interface 存储指针数据,但方法期望值类型,需要 wrapper 来解引用 - if (ast_fndef->self_kind == PARAM_SELF_T && ast_fndef->receiver_wrapper == NULL && typedef_stmt->type_expr. - storage_kind != STORAGE_KIND_PTR) { - ast_fndef_t *wrapper_fn = generate_receiver_wrapper(m, ast_fndef, ast_fndef->impl_type); - ast_fndef->receiver_wrapper = wrapper_fn; - symbol_table_set(wrapper_fn->symbol_name, SYMBOL_FN, wrapper_fn, false); - infer_fn_decl(m, wrapper_fn, type_kind_new(TYPE_UNKNOWN)); - - linked_push(m->temp_worklist, wrapper_fn); - } - - type_t actual_type = infer_impl_fn_decl(m, ast_fndef); - - // actual_type 由于进行了 rewrite, 所以 param 包含了 self, 而 expect type 没有进行这样的处理。 - // compare - INFER_ASSERTF(type_compare(*expect_type, actual_type), - "the fn '%s' of type '%s' mismatch interface '%s'", ast_fndef->fn_name, typedef_ident, - impl_interface->ident); - } -} - -static void combination_interface(module_t *m, ast_typedef_stmt_t *typedef_stmt, struct sc_map_s64 *visited) { - assert(typedef_stmt->type_expr.status == REDUCTION_STATUS_DONE); - assert(typedef_stmt->type_expr.kind == TYPE_INTERFACE); - type_interface_t *origin_interface = typedef_stmt->type_expr.interface; - struct sc_map_sv exists = {0}; - sc_map_init_sv(&exists, 0, 0); // value is type_fn_t - - for (int i = 0; i < origin_interface->elements->length; ++i) { - type_t *temp = ct_list_value(origin_interface->elements, i); - assert(temp->kind == TYPE_FN); - sc_map_put_sv(&exists, temp->fn->fn_name, temp); - } - - // combination - for (int i = 0; i < typedef_stmt->impl_interfaces->length; ++i) { - type_t *impl_interface = ct_list_value(typedef_stmt->impl_interfaces, i); - *impl_interface = reduction_type_visited(m, *impl_interface, visited); - assert(impl_interface->kind == TYPE_INTERFACE); - for (int j = 0; j < impl_interface->interface->elements->length; ++j) { - type_t *temp = ct_list_value(impl_interface->interface->elements, j); - // check exists - type_t *exist_type = sc_map_get_sv(&exists, temp->fn->fn_name); - if (exist_type) { - // compare - INFER_ASSERTF(type_compare(*exist_type, *temp), "duplicate method '%s'", - temp->fn->fn_name); - - continue; - } - - sc_map_put_sv(&exists, temp->fn->fn_name, temp); - ct_list_push(origin_interface->elements, temp); - } - - if (impl_interface->interface->alloc_types && impl_interface->interface->alloc_types->length > 0) { - if (!origin_interface->alloc_types) { - origin_interface->alloc_types = ct_list_new(sizeof(type_t)); - } - - for (int j = 0; j < impl_interface->interface->alloc_types->length; ++j) { - type_t *temp = ct_list_value(impl_interface->interface->alloc_types, j); - bool exists_type = false; - for (int k = 0; k < origin_interface->alloc_types->length; ++k) { - type_t *origin_alloc = ct_list_value(origin_interface->alloc_types, k); - if (type_compare(*origin_alloc, *temp)) { - exists_type = true; - break; - } - } - - if (!exists_type) { - ct_list_push(origin_interface->alloc_types, temp); - } - } - } - - if (impl_interface->interface->deny_types && impl_interface->interface->deny_types->length > 0) { - if (!origin_interface->deny_types) { - origin_interface->deny_types = ct_list_new(sizeof(type_t)); - } - - for (int j = 0; j < impl_interface->interface->deny_types->length; ++j) { - type_t *temp = ct_list_value(impl_interface->interface->deny_types, j); - bool exists_type = false; - for (int k = 0; k < origin_interface->deny_types->length; ++k) { - type_t *origin_deny = ct_list_value(origin_interface->deny_types, k); - if (type_compare(*origin_deny, *temp)) { - exists_type = true; - break; - } - } - - if (!exists_type) { - ct_list_push(origin_interface->deny_types, temp); - } - } - } - } -} +#define REDUCTION_IDENT_LEAVE_DEPTH() \ + do { \ + if (reduction_ident_depth_entered && t.ident) { \ + uint64_t depth_now = sc_map_get_s64(visited, t.ident); \ + if (depth_now <= 1) { \ + sc_map_del_s64(visited, t.ident); \ + } else { \ + sc_map_put_s64(visited, t.ident, depth_now - 1); \ + } \ + } \ + } while (0) /** * custom_type a = ... @@ -4122,18 +3882,6 @@ static void combination_interface(module_t *m, ast_typedef_stmt_t *typedef_stmt, * @return */ static type_t reduction_type_ident(module_t *m, type_t t, struct sc_map_s64 *visited) { -#define REDUCTION_IDENT_LEAVE_DEPTH() \ - do { \ - if (reduction_ident_depth_entered && t.ident) { \ - uint64_t depth_now = sc_map_get_s64(visited, t.ident); \ - if (depth_now <= 1) { \ - sc_map_del_s64(visited, t.ident); \ - } else { \ - sc_map_put_s64(visited, t.ident, depth_now - 1); \ - } \ - } \ - } while (0) - symbol_t *symbol = symbol_table_get(t.ident); INFER_ASSERTF(symbol, "typedef '%s' not found", t.ident); INFER_ASSERTF(symbol->type == SYMBOL_TYPE, "'%s' is not a type", symbol->ident); @@ -4143,7 +3891,6 @@ static type_t reduction_type_ident(module_t *m, type_t t, struct sc_map_s64 *vis if (!typedef_stmt->params) { INFER_ASSERTF(t.args == NULL, "typedef '%s' args mismatch", t.ident); - // 检查右值是否 reduce 完成 if (typedef_stmt->type_expr.status == REDUCTION_STATUS_DONE) { type_t temp = type_copy(m, typedef_stmt->type_expr); @@ -4184,7 +3931,8 @@ static type_t reduction_type_ident(module_t *m, type_t t, struct sc_map_s64 *vis ast_generics_param_t *param = ct_list_value(typedef_stmt->params, i); - generics_constraints_check(m, ¶m->constraints, arg); + // 类型参数不再进行任何约束, 所有的约束都在 fn 中完成 + // generics_constraints_check(m, ¶m->constraints, arg); table_set(args_table, param->ident, arg); } @@ -4193,21 +3941,6 @@ static type_t reduction_type_ident(module_t *m, type_t t, struct sc_map_s64 *vis stack_push(m->infer_type_args_stack, args_table); } - // 进行 impl 校验, 如果存在泛型,还需要进行泛型展开 - if (typedef_stmt->impl_interfaces) { - if (typedef_stmt->is_interface) { - assert(typedef_stmt->type_expr.status == REDUCTION_STATUS_DONE); - assert(typedef_stmt->type_expr.kind == TYPE_INTERFACE); - combination_interface(m, typedef_stmt, visited); - } else { - for (int i = 0; i < typedef_stmt->impl_interfaces->length; ++i) { - type_t *impl_interface = ct_list_value(typedef_stmt->impl_interfaces, i); - *impl_interface = reduction_type_visited(m, *impl_interface, visited); - check_typedef_impl(m, impl_interface, t.ident, typedef_stmt); - } - } - } - // 对右值进行 copy, 因为泛型会对 type_expr 进行多次展开, 所以需要进行 copy type_t right_type_expr = type_copy(m, typedef_stmt->type_expr); @@ -4241,21 +3974,6 @@ static type_t reduction_type_ident(module_t *m, type_t t, struct sc_map_s64 *vis typedef_stmt->type_expr = reduction_type_visited(m, typedef_stmt->type_expr, visited); - // check impl - if (typedef_stmt->impl_interfaces) { - if (typedef_stmt->is_interface) { - assert(typedef_stmt->type_expr.status == REDUCTION_STATUS_DONE); - assert(typedef_stmt->type_expr.kind == TYPE_INTERFACE); - combination_interface(m, typedef_stmt, visited); - } else { - for (int i = 0; i < typedef_stmt->impl_interfaces->length; ++i) { - type_t *impl_interface = ct_list_value(typedef_stmt->impl_interfaces, i); - *impl_interface = reduction_type_visited(m, *impl_interface, visited); - check_typedef_impl(m, impl_interface, t.ident, typedef_stmt); - } - } - } - type_t right_type_expr = type_copy(m, typedef_stmt->type_expr); t.kind = right_type_expr.kind; t.value = right_type_expr.value; @@ -4263,8 +3981,6 @@ static type_t reduction_type_ident(module_t *m, type_t t, struct sc_map_s64 *vis t.status = right_type_expr.status; REDUCTION_IDENT_LEAVE_DEPTH(); return t; - -#undef REDUCTION_IDENT_LEAVE_DEPTH } static type_t reduction_tagged_union_type(module_t *m, type_t t, struct sc_map_s64 *visited) { @@ -4396,9 +4112,18 @@ static type_t reduction_type_visited(module_t *m, type_t t, struct sc_map_s64 *v } table_t *arg_table = stack_top(m->infer_type_args_stack); - assert(arg_table); - t = type_param_special(m, t, arg_table, visited); + if (!arg_table) { + goto STATUS_DONE; + } + + type_t *arg_type = table_get(arg_table, t.ident); + if (!arg_type) { + goto STATUS_DONE; + } + + assert(arg_table); + t = reduction_type_visited(m, *arg_type, visited); ident = t.ident; ident_kind = t.ident_kind; args = t.args; @@ -4496,6 +4221,7 @@ static type_t infer_impl_fn_decl(module_t *m, ast_fndef_t *fndef) { f->fn_name = fndef->fn_name; f->is_tpl = fndef->is_tpl; f->is_errable = fndef->is_errable; + f->is_fx = fndef->is_fx; f->param_types = ct_list_new(sizeof(type_t)); f->return_type = reduction_type(m, fndef->return_type); f->self_kind = fndef->self_kind; @@ -4539,12 +4265,12 @@ static type_t infer_fn_decl(module_t *m, ast_fndef_t *fndef, type_t target_type) if (fndef->is_generics && m->infer_type_args_stack) { table_t *args_table = stack_top(m->infer_type_args_stack); - assert(args_table); - - for (int i = 0; i < fndef->generics_params->length; i++) { - ast_generics_param_t *param = ct_list_value(fndef->generics_params, i); - INFER_ASSERTF(table_exist(args_table, param->ident), "cannot infer generics fn `%s`", - fndef->fn_name); + if (args_table) { + for (int i = 0; i < fndef->generics_params->length; i++) { + ast_generics_param_t *param = ct_list_value(fndef->generics_params, i); + INFER_ASSERTF(table_exist(args_table, param->ident), "cannot infer generics fn `%s`", + fndef->fn_name); + } } } @@ -4553,6 +4279,7 @@ static type_t infer_fn_decl(module_t *m, ast_fndef_t *fndef, type_t target_type) type_fn->fn_name = fndef->fn_name; type_fn->is_tpl = fndef->is_tpl; type_fn->is_errable = fndef->is_errable; + type_fn->is_fx = fndef->is_fx; type_fn->param_types = ct_list_new(sizeof(type_t)); fndef->return_type.status = REDUCTION_STATUS_UNDO; type_fn->return_type = reduction_type(m, fndef->return_type); @@ -4701,12 +4428,20 @@ void infer(module_t *m) { // infer_worklist // - 遍历所有 fndef 进行处理, 包含 global 和 local fn + // - 跳过来自其他 module infer 产生的泛型特化函数(已经完成 infer,直接保留) + slice_t *already_inferred = slice_new(); for (int i = 0; i < m->ast_fndefs->count; ++i) { ast_fndef_t *fn = m->ast_fndefs->take[i]; if (fn->is_generics) { continue; } + // 泛型特化函数已经在其他 module 的 infer 中完成了推断,不需要再次 infer + if (fn->generics_args_hash) { + slice_push(already_inferred, fn); + continue; + } + // 已经进行了 pre infer 了 assert(fn->type.kind == TYPE_FN); @@ -4714,6 +4449,11 @@ void infer(module_t *m) { } m->ast_fndefs = slice_new(); + // 保留已经完成 infer 的泛型特化函数 + for (int i = 0; i < already_inferred->count; ++i) { + slice_push(m->ast_fndefs, already_inferred->take[i]); + } + // 开始进行 infer, worklist 必须是当前的 infer_worklist // infer 过程中如果调用的函数是一个泛型的函数,则需要根据泛型参数进行泛型函数生成,此时的目标泛型函数可能是其他 module 的函数 @@ -4727,14 +4467,14 @@ void infer(module_t *m) { fn->module->temp_worklist = infer_worklist; // temp_worklist 和 infer_worklist 都是指针指向同一片数据,这也是 worklist 存在的意义 infer_fndef(fn->module, fn); - slice_push(m->ast_fndefs, fn); + slice_push(fn->module->ast_fndefs, fn); for (int j = 0; j < fn->local_children->count; ++j) { ast_fndef_t *child = fn->local_children->take[j]; child->module->temp_worklist = infer_worklist; infer_fndef(child->module, child); - slice_push(m->ast_fndefs, child); + slice_push(fn->module->ast_fndefs, child); } if (fn->generics_args_table) { diff --git a/src/semantic/interface.c b/src/semantic/interface.c new file mode 100644 index 00000000..78ed6ace --- /dev/null +++ b/src/semantic/interface.c @@ -0,0 +1,459 @@ +#include "interface.h" + +#include "src/ast.h" +#include "src/error.h" +#include "src/lir.h" +#include "src/symbol/symbol.h" + +#define INTERFACE_ASSERTF(cond, fmt, ...) \ + { \ + if (!(cond)) { \ + dump_errorf(m, CT_STAGE_INFER, m->current_line, m->current_column, fmt, ##__VA_ARGS__); \ + } \ + } + +ast_fndef_t *generate_receiver_wrapper(module_t *m, ast_fndef_t *origin_fndef); + +static void interface_generate_receiver_wrappers(module_t *m); + +static bool interface_equal(module_t *m, type_t *left, type_t *right) { + int save_line = m->current_line; + int save_column = m->current_column; + + if (!left || !right || !left->ident || !right->ident) { + return false; + } + + if (!str_equal(left->ident, right->ident)) { + return false; + } + + int left_args_len = left->args ? left->args->length : 0; + int right_args_len = right->args ? right->args->length : 0; + if (left_args_len != right_args_len) { + return false; + } + + for (int i = 0; i < left_args_len; ++i) { + type_t *left_arg = ct_list_value(left->args, i); + type_t *right_arg = ct_list_value(right->args, i); + + type_t reduced_left_arg = reduction_type(m, type_copy(m, *left_arg)); + type_t reduced_right_arg = reduction_type(m, type_copy(m, *right_arg)); + if (!type_compare(reduced_left_arg, reduced_right_arg)) { + m->current_line = save_line; + m->current_column = save_column; + return false; + } + } + + m->current_line = save_line; + m->current_column = save_column; + return true; +} + +static type_t interface_extract_fn_type(module_t *m, ast_fndef_t *fndef) { + // method_table only stores instance impl methods + assert(!fndef->is_static); + + type_fn_t *fn = NEW(type_fn_t); + fn->fn_name = fndef->fn_name; + fn->is_tpl = fndef->is_tpl; + fn->is_errable = fndef->is_errable; + fn->is_fx = fndef->is_fx; + fn->param_types = ct_list_new(sizeof(type_t)); + fn->return_type = reduction_type(m, type_copy(m, fndef->return_type)); + + assert(fndef->self_kind != PARAM_SELF_NULL); + // skip self param + int start_index = 1; + for (int i = start_index; i < fndef->params->length; ++i) { + ast_var_decl_t *param = ct_list_value(fndef->params, i); + type_t param_type = reduction_type(m, type_copy(m, param->type)); + ct_list_push(fn->param_types, ¶m_type); + } + + fn->is_rest = fndef->rest_param; + + type_t result = type_new(TYPE_FN, fn); + result.status = REDUCTION_STATUS_DONE; + return result; +} + +/** + * 为值类型接收器生成包装函数 + * 当 self_kind == PARAM_SELF_T 时,interface 存储指针数据但方法期望值类型 + * wrapper 接收指针参数,解引用后调用原函数 + * + * 原函数: fn dog.speak(self) { ... } + * 生成的 wrapper: fn dog.speak_receiver_wrapper(*dog ptr) { return dog.speak(*ptr) } + */ +ast_fndef_t *generate_receiver_wrapper(module_t *m, ast_fndef_t *origin_fndef) { + type_t impl_type = origin_fndef->impl_type; + + // 创建 wrapper 函数定义 + ast_fndef_t *wrapper = ast_fndef_new(m, origin_fndef->line, origin_fndef->column); + wrapper->module = origin_fndef->module; + + // 设置函数名称和符号名 + wrapper->fn_name = dsprintf("%s_receiver_wrapper", origin_fndef->fn_name); + wrapper->symbol_name = dsprintf("%s_receiver_wrapper", origin_fndef->symbol_name); + wrapper->fn_name_with_pkg = dsprintf("%s_receiver_wrapper", origin_fndef->fn_name_with_pkg); + + // 复制返回类型和其他属性 + wrapper->return_type = origin_fndef->return_type; + wrapper->is_errable = origin_fndef->is_errable; + wrapper->is_impl = true; + wrapper->impl_type = impl_type; + wrapper->self_kind = PARAM_SELF_REF_T; // wrapper 接收指针参数 + + // 复制泛型参数 + wrapper->generics_params = origin_fndef->generics_params; + wrapper->is_generics = origin_fndef->is_generics; + wrapper->is_tpl = origin_fndef->is_tpl; + + // 创建参数列表 - 第一个参数是 ref + wrapper->params = ct_list_new(sizeof(ast_var_decl_t)); + + // 为 self 参数生成唯一标识符并注册到符号表 + char *self_unique_ident = var_unique_ident(m, FN_SELF_NAME); + ast_var_decl_t *self_param = NEW(ast_var_decl_t); + self_param->ident = self_unique_ident; + self_param->type = type_refof(impl_type); + symbol_table_set(self_unique_ident, SYMBOL_VAR, self_param, true); + ct_list_push(wrapper->params, self_param); + + // 复制原函数的其他参数(跳过第一个 self 参数) + for (int i = 1; i < origin_fndef->params->length; ++i) { + ast_var_decl_t *param = ct_list_value(origin_fndef->params, i); + ct_list_push(wrapper->params, param); + } + + // 构建函数体:return origin_fn(*self, other_args...) + wrapper->body = slice_new(); + + // 创建解引用表达式: *self (使用唯一标识符) + ast_unary_expr_t *deref_expr = NEW(ast_unary_expr_t); + deref_expr->op = AST_OP_IA; // indirect address (dereference) + deref_expr->operand = (ast_expr_t){ + .assert_type = AST_EXPR_IDENT, + .value = ast_new_ident(self_unique_ident), + .line = origin_fndef->line, + .column = origin_fndef->column, + }; + + // 创建 call 表达式 + ast_call_t *call = NEW(ast_call_t); + call->left = (ast_expr_t){ + .assert_type = AST_EXPR_IDENT, + .value = ast_new_ident(origin_fndef->symbol_name), + .line = origin_fndef->line, + .column = origin_fndef->column, + }; + call->args = ct_list_new(sizeof(ast_expr_t)); + call->spread = false; + call->inject_self_arg = true; + + // 转发泛型参数作为 generics_args + if (origin_fndef->generics_params && origin_fndef->generics_params->length > 0) { + call->generics_args = ct_list_new(sizeof(type_t)); + for (int i = 0; i < origin_fndef->generics_params->length; ++i) { + ast_generics_param_t *gp = ct_list_value(origin_fndef->generics_params, i); + type_t arg_type = type_ident_new(gp->ident, TYPE_IDENT_GENERICS_PARAM); + ct_list_push(call->generics_args, &arg_type); + } + } else { + call->generics_args = NULL; + } + + // 第一个参数是解引用的 self + ast_expr_t deref_arg = { + .assert_type = AST_EXPR_UNARY, + .value = deref_expr, + .line = origin_fndef->line, + .column = origin_fndef->column, + }; + ct_list_push(call->args, &deref_arg); + + // 添加其他参数 + for (int i = 1; i < origin_fndef->params->length; ++i) { + ast_var_decl_t *param = ct_list_value(origin_fndef->params, i); + ast_expr_t arg = { + .assert_type = AST_EXPR_IDENT, + .value = ast_new_ident(param->ident), + .line = origin_fndef->line, + .column = origin_fndef->column, + }; + ct_list_push(call->args, &arg); + } + + // 创建 return 语句 + ast_return_stmt_t *ret_stmt = NEW(ast_return_stmt_t); + if (origin_fndef->return_type.kind != TYPE_VOID) { + ret_stmt->expr = NEW(ast_expr_t); + ret_stmt->expr->assert_type = AST_CALL; + ret_stmt->expr->value = call; + ret_stmt->expr->line = origin_fndef->line; + ret_stmt->expr->column = origin_fndef->column; + } else { + // void 返回类型,只调用不 return + ret_stmt->expr = NULL; + } + + ast_stmt_t *stmt = NEW(ast_stmt_t); + if (origin_fndef->return_type.kind != TYPE_VOID) { + stmt->assert_type = AST_STMT_RETURN; + stmt->value = ret_stmt; + } else { + // void 返回类型,改为表达式语句 + stmt->assert_type = AST_CALL; + stmt->value = call; + } + stmt->line = origin_fndef->line; + stmt->column = origin_fndef->column; + slice_push(wrapper->body, stmt); + + return wrapper; +} + +static void interface_generate_receiver_wrappers(module_t *m) { + int fndef_count = m->ast_fndefs->count; + for (int i = 0; i < fndef_count; ++i) { + ast_fndef_t *ast_fn = m->ast_fndefs->take[i]; + if (!ast_fn->is_impl || ast_fn->is_static || ast_fn->receiver_wrapper_ident) { + continue; + } + + if (ast_fn->self_kind != PARAM_SELF_T || ast_fn->impl_type.ident_kind != TYPE_IDENT_DEF) { + continue; + } + + symbol_t *type_symbol = symbol_table_get(ast_fn->impl_type.ident); + INTERFACE_ASSERTF(type_symbol && type_symbol->type == SYMBOL_TYPE, "type '%s' undeclared", + ast_fn->impl_type.ident); + if (!type_symbol || type_symbol->type != SYMBOL_TYPE) { + continue; + } + + type_t impl_type = reduction_type(m, type_copy(m, ast_fn->impl_type)); + if (!(ast_fn->self_kind == PARAM_SELF_T && impl_type.storage_kind != STORAGE_KIND_PTR)) { + continue; + } + + m->current_line = ast_fn->line; + m->current_column = ast_fn->column; + ast_fndef_t *wrapper_fn = generate_receiver_wrapper(m, ast_fn); + + symbol_t *wrapper_symbol = symbol_table_set(wrapper_fn->symbol_name, SYMBOL_FN, wrapper_fn, false); + INTERFACE_ASSERTF(wrapper_symbol, "ident '%s' redeclared", wrapper_fn->symbol_name); + ast_fn->receiver_wrapper_ident = wrapper_fn->symbol_name; + + if (!wrapper_symbol) { + continue; + } + + slice_push(wrapper_fn->module->ast_fndefs, wrapper_fn); + } +} + +/** + * 递归查找 stmt 中是否包含 target_interface + */ +bool check_impl_interface_contains(module_t *m, ast_typedef_stmt_t *stmt, type_t *find_target_interface) { + int save_line = m->current_line; + int save_column = m->current_column; + + if (!stmt->impl_interfaces) { + m->current_line = save_line; + m->current_column = save_column; + return false; + } + + for (int i = 0; i < stmt->impl_interfaces->length; ++i) { + type_t *impl_interface = ct_list_value(stmt->impl_interfaces, i); + if (interface_equal(m, impl_interface, find_target_interface)) { + m->current_line = save_line; + m->current_column = save_column; + return true; + } + + symbol_t *s = symbol_table_get(impl_interface->ident); + if (!s) { + continue; + } + + assert(s->type == SYMBOL_TYPE); + ast_typedef_stmt_t *typedef_stmt = s->ast_value; + if (typedef_stmt->impl_interfaces == NULL) { + continue; + } + + if (check_impl_interface_contains(m, typedef_stmt, find_target_interface)) { + m->current_line = save_line; + m->current_column = save_column; + return true; + } + } + + m->current_line = save_line; + m->current_column = save_column; + return false; +} + +static void interface_combination_typedef(module_t *m, ast_typedef_stmt_t *typedef_stmt) { + if (!typedef_stmt->is_interface || !typedef_stmt->impl_interfaces || typedef_stmt->impl_interfaces->length == 0) { + return; + } + + m->current_line = typedef_stmt->type_expr.line; + m->current_column = typedef_stmt->type_expr.column; + + typedef_stmt->type_expr = reduction_type(m, typedef_stmt->type_expr); + INTERFACE_ASSERTF(typedef_stmt->type_expr.kind == TYPE_INTERFACE, "interface '%s' type invalid", + typedef_stmt->ident); + + type_interface_t *origin_interface = typedef_stmt->type_expr.interface; + struct sc_map_sv exists = {0}; + sc_map_init_sv(&exists, 0, 0); // value is type_t* + + for (int i = 0; i < origin_interface->elements->length; ++i) { + type_t *method = ct_list_value(origin_interface->elements, i); + INTERFACE_ASSERTF(method->kind == TYPE_FN, "interface '%s' contains non-fn method", typedef_stmt->ident); + INTERFACE_ASSERTF(method->fn && method->fn->fn_name, "interface '%s' method invalid", typedef_stmt->ident); + sc_map_put_sv(&exists, method->fn->fn_name, method); + } + + // merge composed interfaces + for (int i = 0; i < typedef_stmt->impl_interfaces->length; ++i) { + type_t *impl_interface = ct_list_value(typedef_stmt->impl_interfaces, i); + m->current_line = impl_interface->line; + m->current_column = impl_interface->column; + + *impl_interface = reduction_type(m, *impl_interface); + INTERFACE_ASSERTF(impl_interface->kind == TYPE_INTERFACE, "interface '%s' impl target '%s' is not interface", + typedef_stmt->ident, impl_interface->ident); + + for (int j = 0; j < impl_interface->interface->elements->length; ++j) { + type_t *method = ct_list_value(impl_interface->interface->elements, j); + type_t *exist_method = sc_map_get_sv(&exists, method->fn->fn_name); + if (exist_method) { + INTERFACE_ASSERTF(type_compare(*exist_method, *method), "duplicate method '%s'", method->fn->fn_name); + continue; + } + + sc_map_put_sv(&exists, method->fn->fn_name, method); + ct_list_push(origin_interface->elements, method); + } + + if (impl_interface->interface->alloc_types && impl_interface->interface->alloc_types->length > 0) { + if (!origin_interface->alloc_types) { + origin_interface->alloc_types = ct_list_new(sizeof(type_t)); + } + + for (int j = 0; j < impl_interface->interface->alloc_types->length; ++j) { + type_t *alloc_type = ct_list_value(impl_interface->interface->alloc_types, j); + bool exists_type = false; + for (int k = 0; k < origin_interface->alloc_types->length; ++k) { + type_t *origin_alloc = ct_list_value(origin_interface->alloc_types, k); + if (type_compare(*origin_alloc, *alloc_type)) { + exists_type = true; + break; + } + } + + if (!exists_type) { + ct_list_push(origin_interface->alloc_types, alloc_type); + } + } + } + + if (impl_interface->interface->deny_types && impl_interface->interface->deny_types->length > 0) { + if (!origin_interface->deny_types) { + origin_interface->deny_types = ct_list_new(sizeof(type_t)); + } + + for (int j = 0; j < impl_interface->interface->deny_types->length; ++j) { + type_t *deny_type = ct_list_value(impl_interface->interface->deny_types, j); + bool exists_type = false; + for (int k = 0; k < origin_interface->deny_types->length; ++k) { + type_t *origin_deny = ct_list_value(origin_interface->deny_types, k); + if (type_compare(*origin_deny, *deny_type)) { + exists_type = true; + break; + } + } + + if (!exists_type) { + ct_list_push(origin_interface->deny_types, deny_type); + } + } + } + } +} + +static void interface_check_typedef_impl(module_t *m, ast_typedef_stmt_t *typedef_stmt, type_t *impl_interface) { + if (impl_interface->ident_kind != TYPE_IDENT_INTERFACE) { + return; + } + + m->current_line = impl_interface->line; + m->current_column = impl_interface->column; + + *impl_interface = reduction_type(m, *impl_interface); + INTERFACE_ASSERTF(impl_interface->kind == TYPE_INTERFACE, "type '%s' impl target '%s' is not interface", + typedef_stmt->ident, impl_interface->ident); + + type_interface_t *interface_type = impl_interface->interface; + if (!interface_type || interface_type->elements->length == 0) { + return; + } + + for (int i = 0; i < interface_type->elements->length; ++i) { + type_t *expect_type = ct_list_value(interface_type->elements, i); + INTERFACE_ASSERTF(expect_type->kind == TYPE_FN, "interface '%s' contains non-fn constraint", + impl_interface->ident); + + type_fn_t *interface_fn_type = expect_type->fn; + INTERFACE_ASSERTF(interface_fn_type && interface_fn_type->fn_name, "interface '%s' fn invalid", + impl_interface->ident); + + char *fn_ident = str_connect_by(typedef_stmt->ident, interface_fn_type->fn_name, IMPL_CONNECT_IDENT); + ast_fndef_t *impl_method = sc_map_get_sv(&typedef_stmt->method_table, fn_ident); + INTERFACE_ASSERTF(impl_method, "type '%s' not impl fn '%s' for interface '%s'", + typedef_stmt->ident, interface_fn_type->fn_name, impl_interface->ident); + + m->current_line = impl_method->line; + m->current_column = impl_method->column; + + type_t actual_type = interface_extract_fn_type(m, impl_method); + INTERFACE_ASSERTF(type_compare(*expect_type, actual_type), + "the fn '%s' of type '%s' mismatch interface '%s'", + impl_method->fn_name, typedef_stmt->ident, impl_interface->ident); + } +} + +void interface(module_t *m) { + // reduction 过程中可能触发 impl check(内部会写入 temp_worklist) + if (m->temp_worklist == NULL) { + m->temp_worklist = linked_new(); + } + + interface_generate_receiver_wrappers(m); + + for (int i = 0; i < m->ast_typedefs->count; ++i) { + ast_typedef_stmt_t *typedef_stmt = m->ast_typedefs->take[i]; + if (!typedef_stmt->impl_interfaces || typedef_stmt->impl_interfaces->length == 0) { + continue; + } + + if (typedef_stmt->is_interface) { + interface_combination_typedef(m, typedef_stmt); + continue; + } + + for (int j = 0; j < typedef_stmt->impl_interfaces->length; ++j) { + type_t *impl_interface = ct_list_value(typedef_stmt->impl_interfaces, j); + interface_check_typedef_impl(m, typedef_stmt, impl_interface); + } + } +} diff --git a/src/semantic/interface.h b/src/semantic/interface.h new file mode 100644 index 00000000..dc2d5fd8 --- /dev/null +++ b/src/semantic/interface.h @@ -0,0 +1,11 @@ +#ifndef NATURE_SRC_SEMANTIC_INTERFACE_H_ +#define NATURE_SRC_SEMANTIC_INTERFACE_H_ + +#include "src/ast.h" + + +void interface(module_t *m); + +bool check_impl_interface_contains(module_t *m, ast_typedef_stmt_t *stmt, type_t *find_target_interface); + +#endif // NATURE_SRC_SEMANTIC_INTERFACE_H_ diff --git a/src/syntax/parser.c b/src/syntax/parser.c index 19265997..7c2646ac 100644 --- a/src/syntax/parser.c +++ b/src/syntax/parser.c @@ -28,8 +28,27 @@ static ast_expr_t parser_match_expr(module_t *m); static ast_tuple_destr_t *parser_var_tuple_destr(module_t *m); +static ast_stmt_t *parser_defer_stmt(module_t *m); + static int64_t parser_test_unique = 0; +static table_t *parser_clone_type_params_table(table_t *source) { + table_t *target = table_new(); + if (!source || source->count == 0) { + return target; + } + + for (int i = 0; i < source->capacity; ++i) { + table_entry *entry = &source->entries[i]; + if (!entry->key) { + continue; + } + table_set(target, entry->key, entry->value); + } + + return target; +} + static token_t *parser_advance(module_t *m) { assert(m->p_cursor.current->succ != NULL && "next token_t is null"); token_t *t = m->p_cursor.current->value; @@ -68,7 +87,8 @@ static bool parser_is(module_t *m, token_type_t expect) { } static bool ident_is_builtin_type(module_t *m, token_t *token) { - if (str_equal(token->literal, "vec") || str_equal(token->literal, "map") || str_equal(token->literal, "set") || str_equal(token->literal, "tup")) { + if (str_equal(token->literal, "vec") || str_equal(token->literal, "map") || str_equal(token->literal, "set") || + str_equal(token->literal, "tup")) { return true; } return false; @@ -203,8 +223,8 @@ static ast_expr_t *expr_new_ptr(module_t *m) { static ast_expr_t expr_new(module_t *m) { ast_expr_t result = { - .line = parser_peek(m)->line, - .column = parser_peek(m)->column, + .line = parser_peek(m)->line, + .column = parser_peek(m)->column, }; return result; } @@ -275,7 +295,8 @@ static list_t *parser_parse_where_constraints(module_t *m) { list_t *where_params = ct_list_new(sizeof(ast_generics_param_t)); PARSER_ASSERTF(!parser_is(m, TOKEN_STMT_EOF), "#where must declare at least one generic constraint"); - while (!parser_is(m, TOKEN_STMT_EOF) && !parser_is(m, TOKEN_EOF) && !parser_is(m, TOKEN_FN)) { + while (!parser_is(m, TOKEN_STMT_EOF) && !parser_is(m, TOKEN_EOF) && + !parser_is(m, TOKEN_FN) && !parser_is(m, TOKEN_FX)) { token_t *ident = parser_must(m, TOKEN_IDENT); ast_generics_param_t *param = ast_generics_param_new(ident->line, ident->column, ident->literal); parser_must(m, TOKEN_COLON); @@ -296,7 +317,8 @@ static list_t *parser_parse_where_constraints(module_t *m) { } // 允许 #where 最后一个约束后保留逗号 - if (parser_is(m, TOKEN_STMT_EOF) || parser_is(m, TOKEN_EOF) || parser_is(m, TOKEN_FN)) { + if (parser_is(m, TOKEN_STMT_EOF) || parser_is(m, TOKEN_EOF) || + parser_is(m, TOKEN_FN) || parser_is(m, TOKEN_FX)) { break; } } @@ -362,8 +384,9 @@ static slice_t *parser_body(module_t *m, bool last_to_ret) { return stmt_list; } -static inline type_fn_t *parser_type_fn(module_t *m) { +static inline type_fn_t *parser_type_fn(module_t *m, bool is_fx) { type_fn_t *type_fn = NEW(type_fn_t); + type_fn->is_fx = is_fx; type_fn->param_types = ct_list_new(sizeof(type_t)); parser_must(m, TOKEN_LEFT_PAREN); @@ -384,7 +407,8 @@ static inline type_fn_t *parser_type_fn(module_t *m) { } if (type_fn->is_rest) { - PARSER_ASSERTF(parser_is(m, TOKEN_RIGHT_PAREN), "can only use '...' as the final argument in the fn parameters"); + PARSER_ASSERTF(parser_is(m, TOKEN_RIGHT_PAREN), + "can only use '...' as the final argument in the fn parameters"); } } while (parser_consume(m, TOKEN_COMMA)); @@ -429,8 +453,8 @@ static type_t parser_type(module_t *m) { // T?, T? 后面不在允许直接携带 | if (parser_consume(m, TOKEN_QUESTION)) { type_t union_type = { - .status = REDUCTION_STATUS_UNDO, - .kind = TYPE_UNION, + .status = REDUCTION_STATUS_UNDO, + .kind = TYPE_UNION, }; union_type.union_ = NEW(type_union_t); union_type.union_->elements = ct_list_new(sizeof(type_t)); @@ -456,12 +480,12 @@ static type_t parser_type(module_t *m) { */ static type_t parser_single_type(module_t *m) { type_t result = { - .status = REDUCTION_STATUS_UNDO, - .line = parser_peek(m)->line, - .column = parser_peek(m)->column, - .ident = NULL, - .ident_kind = 0, - .args = NULL, + .status = REDUCTION_STATUS_UNDO, + .line = parser_peek(m)->line, + .column = parser_peek(m)->column, + .ident = NULL, + .ident_kind = 0, + .args = NULL, }; // any 特殊处理 @@ -657,9 +681,14 @@ static type_t parser_single_type(module_t *m) { return result; } - // fn(int, int):int! - if (parser_consume(m, TOKEN_FN)) { - type_fn_t *type_fn = parser_type_fn(m); + // fn(int, int):int! / fx(int, int):int! + if (parser_is(m, TOKEN_FN) || parser_is(m, TOKEN_FX)) { + bool is_fx = parser_consume(m, TOKEN_FX); + if (!is_fx) { + parser_must(m, TOKEN_FN); + } + + type_fn_t *type_fn = parser_type_fn(m, is_fx); result.kind = TYPE_FN; result.fn = type_fn; return result; @@ -787,12 +816,12 @@ static ast_stmt_t *parser_typedef_stmt(module_t *m) { } type_t t = { - .status = REDUCTION_STATUS_UNDO, - .line = parser_peek(m)->line, - .column = parser_peek(m)->column, - .ident = NULL, - .args = NULL, - .ident_kind = 0, + .status = REDUCTION_STATUS_UNDO, + .line = parser_peek(m)->line, + .column = parser_peek(m)->column, + .ident = NULL, + .args = NULL, + .ident_kind = 0, }; t.kind = TYPE_STRUCT; t.struct_ = type_struct; @@ -832,12 +861,12 @@ static ast_stmt_t *parser_typedef_stmt(module_t *m) { } type_t t = { - .status = REDUCTION_STATUS_UNDO, - .line = parser_peek(m)->line, - .column = parser_peek(m)->column, - .ident = NULL, - .args = NULL, - .ident_kind = 0, + .status = REDUCTION_STATUS_UNDO, + .line = parser_peek(m)->line, + .column = parser_peek(m)->column, + .ident = NULL, + .args = NULL, + .ident_kind = 0, }; t.kind = TYPE_TAGGED_UNION; t.tagged_union = tagged_union; @@ -858,12 +887,36 @@ static ast_stmt_t *parser_typedef_stmt(module_t *m) { sc_map_init_s64(&exists, 0, 0); // value is type_fn_t while (!parser_consume(m, TOKEN_RIGHT_CURLY)) { - parser_must(m, TOKEN_FN); + INFER_ASSERTF(parser_is(m, TOKEN_FX) || parser_is(m, TOKEN_FN), "interface only supports fn and fx"); + bool is_fx = parser_consume(m, TOKEN_FX); + if (!is_fx) { + parser_must(m, TOKEN_FN); + } + // ident char *fn_name = parser_must(m, TOKEN_IDENT)->literal; - type_fn_t *type_fn = parser_type_fn(m); + list_t *method_generics_params = NULL; + table_t *origin_type_params_table = m->parser_type_params_table; + table_t *method_type_params_table = NULL; + if (parser_consume(m, TOKEN_LEFT_ANGLE)) { + method_type_params_table = parser_clone_type_params_table(origin_type_params_table); + m->parser_type_params_table = method_type_params_table; + parser_parse_generics_decl(m, &method_generics_params); + parser_must(m, TOKEN_RIGHT_ANGLE); + } + + type_fn_t *type_fn = parser_type_fn(m, false); type_fn->fn_name = fn_name; + type_fn->is_fx = is_fx; + if (method_generics_params && method_generics_params->length > 0) { + type_fn->is_tpl = true; + } + + if (method_type_params_table) { + table_free(method_type_params_table); + m->parser_type_params_table = origin_type_params_table; + } if (sc_map_get_s64(&exists, fn_name)) { PARSER_ASSERTF(false, "interface method '%s' exists", fn_name); @@ -872,14 +925,14 @@ static ast_stmt_t *parser_typedef_stmt(module_t *m) { sc_map_put_s64(&exists, fn_name, 1); type_t interface_item = { - .status = REDUCTION_STATUS_UNDO, - .line = parser_peek(m)->line, - .column = parser_peek(m)->column, - .ident = NULL, - .ident_kind = 0, - .args = NULL, - .kind = TYPE_FN, - .fn = type_fn, + .status = REDUCTION_STATUS_UNDO, + .line = parser_peek(m)->line, + .column = parser_peek(m)->column, + .ident = NULL, + .ident_kind = 0, + .args = NULL, + .kind = TYPE_FN, + .fn = type_fn, }; ct_list_push(type_interface->elements, &interface_item); @@ -887,14 +940,14 @@ static ast_stmt_t *parser_typedef_stmt(module_t *m) { } type_t t = { - .status = REDUCTION_STATUS_UNDO, - .line = parser_peek(m)->line, - .column = parser_peek(m)->column, - .ident = NULL, - .ident_kind = 0, - .args = NULL, - .kind = TYPE_INTERFACE, - .interface = type_interface, + .status = REDUCTION_STATUS_UNDO, + .line = parser_peek(m)->line, + .column = parser_peek(m)->column, + .ident = NULL, + .ident_kind = 0, + .args = NULL, + .kind = TYPE_INTERFACE, + .interface = type_interface, }; typedef_stmt->type_expr = t; @@ -955,12 +1008,12 @@ static ast_stmt_t *parser_typedef_stmt(module_t *m) { parser_must(m, TOKEN_RIGHT_CURLY); type_t t = { - .status = REDUCTION_STATUS_UNDO, - .line = parser_peek(m)->line, - .column = parser_peek(m)->column, - .ident = NULL, - .args = NULL, - .ident_kind = 0, + .status = REDUCTION_STATUS_UNDO, + .line = parser_peek(m)->line, + .column = parser_peek(m)->column, + .ident = NULL, + .args = NULL, + .ident_kind = 0, }; t.kind = TYPE_ENUM; t.enum_ = type_enum; @@ -976,8 +1029,8 @@ static ast_stmt_t *parser_typedef_stmt(module_t *m) { if (parser_consume(m, TOKEN_QUESTION)) { type_t union_type = { - .status = REDUCTION_STATUS_UNDO, - .kind = TYPE_UNION, + .status = REDUCTION_STATUS_UNDO, + .kind = TYPE_UNION, }; union_type.union_ = NEW(type_union_t); union_type.union_->elements = ct_list_new(sizeof(type_t)); @@ -1032,13 +1085,13 @@ static ast_stmt_t *parser_typedef_stmt(module_t *m) { */ static type_t ast_expr_to_typedef_ident(module_t *m, ast_expr_t left, list_t *generics_args) { type_t t = { - .status = REDUCTION_STATUS_UNDO, - .line = parser_peek(m)->line, - .column = parser_peek(m)->column, - .ident = NULL, - .ident_kind = TYPE_IDENT_DEF, - .kind = TYPE_IDENT, - .args = NULL, + .status = REDUCTION_STATUS_UNDO, + .line = parser_peek(m)->line, + .column = parser_peek(m)->column, + .ident = NULL, + .ident_kind = TYPE_IDENT_DEF, + .kind = TYPE_IDENT, + .args = NULL, }; // 重新整理一下左值,整理成 typedef_t @@ -1122,7 +1175,8 @@ static void parser_params(module_t *m, ast_fndef_t *fndef) { ct_list_push(fndef->params, ref); if (fndef->rest_param) { - PARSER_ASSERTF(parser_is(m, TOKEN_RIGHT_PAREN), "can only use '...' as the final argument in the fn parsms"); + PARSER_ASSERTF(parser_is(m, TOKEN_RIGHT_PAREN), + "can only use '...' as the final argument in the fn parsms"); } } while (parser_consume(m, TOKEN_COMMA)); @@ -1213,7 +1267,8 @@ static bool parser_left_angle_is_type_args(module_t *m, ast_expr_t left) { goto RET; } - if (!parser_next_is(m, 1, TOKEN_LEFT_CURLY) && !parser_next_is(m, 1, TOKEN_LEFT_PAREN) && !parser_next_is(m, 1, TOKEN_DOT)) { + if (!parser_next_is(m, 1, TOKEN_LEFT_CURLY) && !parser_next_is(m, 1, TOKEN_LEFT_PAREN) && !parser_next_is( + m, 1, TOKEN_DOT)) { result = false; goto RET; } @@ -1600,7 +1655,8 @@ static ast_expr_t parser_access(module_t *m, ast_expr_t left) { ast_expr_t result = expr_new(m); parser_must(m, TOKEN_LEFT_SQUARE); - if (parser_consume(m, TOKEN_RANGE)) { // list[..expr] | list[..] + if (parser_consume(m, TOKEN_RANGE)) { + // list[..expr] | list[..] ast_vec_slice_t *slice = mallocz(sizeof(ast_vec_slice_t)); slice->left = left; slice->start = *ast_int_expr(result.line, result.column, 0); @@ -1617,7 +1673,8 @@ static ast_expr_t parser_access(module_t *m, ast_expr_t left) { } ast_expr_t first = parser_expr(m); - if (parser_consume(m, TOKEN_RANGE)) { // list[expr..expr] | list[expr..] + if (parser_consume(m, TOKEN_RANGE)) { + // list[expr..expr] | list[expr..] ast_vec_slice_t *slice = mallocz(sizeof(ast_vec_slice_t)); slice->left = left; slice->start = first; @@ -1872,7 +1929,7 @@ static bool is_call_generics(module_t *m) { * {x} a = xxx * [x] a = xxx * (x, x, x) a = xxx - * fn(x):x a = xxx // 区分 fn a(x): x {} + * fn(x):x a = xxx / fx(x):x a = xxx // 区分 fn a(x): x {} * custom_x a = xxx # 连续两个 ident 判定就能判定出来 * @return */ @@ -1896,7 +1953,8 @@ static bool is_type_begin_stmt(module_t *m) { } // fndef type (stmt 维度禁止了匿名 fndef, 所以这里一定是 fndef type) - if (parser_is(m, TOKEN_FN) && parser_next_is(m, 1, TOKEN_LEFT_PAREN)) { + if ((parser_is(m, TOKEN_FN) || parser_is(m, TOKEN_FX)) && + parser_next_is(m, 1, TOKEN_LEFT_PAREN)) { return true; } @@ -1982,7 +2040,17 @@ static ast_stmt_t *parser_for_stmt(module_t *m) { } parser_must(m, TOKEN_IN); - for_iterator_stmt->iterate = parser_precedence_expr(m, PRECEDENCE_TYPE_CAST, 0); + + ast_expr_t in_expr = parser_precedence_expr(m, PRECEDENCE_TYPE_CAST, TOKEN_RANGE); + if (parser_consume(m, TOKEN_RANGE)) { + PARSER_ASSERTF(for_iterator_stmt->second == NULL, "for range only supports one iterator variable"); + + for_iterator_stmt->is_range = true; + for_iterator_stmt->range_start = in_expr; + for_iterator_stmt->range_end = parser_precedence_expr(m, PRECEDENCE_TYPE_CAST, 0); + } else { + for_iterator_stmt->iterate = in_expr; + } for_iterator_stmt->body = parser_body(m, false); @@ -2220,6 +2288,25 @@ static ast_stmt_t *parser_return_stmt(module_t *m) { return result; } +static ast_stmt_t *parser_defer_stmt(module_t *m) { + ast_stmt_t *result = stmt_new(m); + parser_must(m, TOKEN_DEFER); + + ast_defer_stmt_t *stmt = NEW(ast_defer_stmt_t); + if (parser_is(m, TOKEN_LEFT_CURLY)) { + stmt->body = parser_body(m, false); + } else { + PARSER_ASSERTF(!parser_is_stmt_eof(m) && !parser_is(m, TOKEN_RIGHT_CURLY), + "defer must have statement body"); + stmt->body = slice_new(); + slice_push(stmt->body, parser_local_stmt(m)); + } + + result->assert_type = AST_STMT_DEFER; + result->value = stmt; + return result; +} + static ast_stmt_t *parser_import_stmt(module_t *m) { ast_stmt_t *result = stmt_new(m); parser_advance(m); @@ -2424,7 +2511,8 @@ static ast_expr_t parser_left_curly_expr(module_t *m) { } ast_expr_t key_expr = parser_expr(m); - if (parser_consume(m, TOKEN_COLON)) { // k:v + if (parser_consume(m, TOKEN_COLON)) { + // k:v // map ast_map_new_t *map_new = NEW(ast_map_new_t); map_new->elements = ct_list_new(sizeof(ast_map_element_t)); @@ -2493,7 +2581,12 @@ static ast_expr_t parser_left_curly_expr(module_t *m) { static ast_expr_t parser_fndef_expr(module_t *m) { ast_expr_t result = expr_new(m); ast_fndef_t *fndef = ast_fndef_new(m, parser_peek(m)->line, parser_peek(m)->column); - parser_must(m, TOKEN_FN); + if (parser_is(m, TOKEN_FX)) { + parser_advance(m); + fndef->is_fx = true; + } else { + parser_must(m, TOKEN_FN); + } if (parser_is(m, TOKEN_IDENT)) { PARSER_ASSERTF(false, "closure fn cannot have a name"); @@ -2507,7 +2600,6 @@ static ast_expr_t parser_fndef_expr(module_t *m) { if (parser_consume(m, TOKEN_COLON)) { fndef->return_type = parser_type(m); - } else { fndef->return_type = type_kind_new(TYPE_VOID); fndef->return_type.line = parser_peek(m)->line; @@ -2572,7 +2664,6 @@ static ast_expr_t parser_new_expr(module_t *m) { } } } else { - new_expr->default_expr = expr_new_ptr(m); *new_expr->default_expr = parser_expr(m); @@ -2581,8 +2672,9 @@ static ast_expr_t parser_new_expr(module_t *m) { new_expr->properties = ct_list_new(sizeof(struct_property_t)); ast_ident *ident = new_expr->default_expr->value; struct_property_t item = { - .name = strdup(ident->literal), - .right = ast_ident_expr(parser_peek(m)->line, parser_peek(m)->column, strdup(ident->literal))}; + .name = strdup(ident->literal), + .right = ast_ident_expr(parser_peek(m)->line, parser_peek(m)->column, strdup(ident->literal)) + }; ct_list_push(new_expr->properties, &item); } } @@ -2813,7 +2905,12 @@ static ast_stmt_t *parser_fndef_stmt(module_t *m, ast_fndef_t *fndef) { result->assert_type = AST_FNDEF; result->value = fndef; - parser_must(m, TOKEN_FN); + if (parser_is(m, TOKEN_FX)) { + parser_advance(m); + fndef->is_fx = true; + } else { + parser_must(m, TOKEN_FN); + } // 第一个绝对是 ident, 第二个如果是 . 或者 < 则说明是类型扩展 if (parser_is_impl_fn(m)) { @@ -2887,7 +2984,8 @@ static ast_stmt_t *parser_fndef_stmt(module_t *m, ast_fndef_t *fndef) { // 类型检测 - PARSER_ASSERTF(is_impl_builtin_type(impl_type.kind) || impl_type.kind == TYPE_IDENT, "type '%s' cannot impl fn", type_kind_str[impl_type.kind]); + PARSER_ASSERTF(is_impl_builtin_type(impl_type.kind) || impl_type.kind == TYPE_IDENT, "type '%s' cannot impl fn", + type_kind_str[impl_type.kind]); fndef->impl_type = impl_type; @@ -3016,16 +3114,16 @@ static ast_stmt_t *parser_label(module_t *m) { } if (fndef->pending_where_params) { - PARSER_ASSERTF(parser_is(m, TOKEN_FN), "#where can only be applied to fn"); + PARSER_ASSERTF(parser_is(m, TOKEN_FN) || parser_is(m, TOKEN_FX), "#where can only be applied to fn/fx"); } if (parser_is(m, TOKEN_TYPE)) { - PARSER_ASSERTF(!fndef->pending_where_params, "#where can only be applied to fn"); + PARSER_ASSERTF(!fndef->pending_where_params, "#where can only be applied to fn/fx"); return parser_typedef_stmt(m); - } else if (parser_is(m, TOKEN_FN)) { + } else if (parser_is(m, TOKEN_FN) || parser_is(m, TOKEN_FX)) { return parser_fndef_stmt(m, fndef); } else { - PARSER_ASSERTF(false, "the label can only be applied to type alias or fn."); + PARSER_ASSERTF(false, "the label can only be applied to type alias or fn/fx."); } } @@ -3137,6 +3235,8 @@ static ast_stmt_t *parser_local_stmt(module_t *m) { return parser_for_stmt(m); } else if (parser_is(m, TOKEN_RETURN)) { return parser_return_stmt(m); + } else if (parser_is(m, TOKEN_DEFER)) { + return parser_defer_stmt(m); } else if (parser_is(m, TOKEN_IMPORT)) { return parser_import_stmt(m); } else if (parser_is(m, TOKEN_TYPE)) { @@ -3177,7 +3277,7 @@ static ast_stmt_t *parser_global_stmt(module_t *m) { return parser_type_begin_stmt(m); } else if (parser_is(m, TOKEN_LABEL)) { return parser_label(m); - } else if (parser_is(m, TOKEN_FN)) { + } else if (parser_is(m, TOKEN_FN) || parser_is(m, TOKEN_FX)) { return parser_fndef_stmt(m, ast_fndef_new(m, parser_peek(m)->line, parser_peek(m)->column)); } else if (parser_is(m, TOKEN_TEST)) { return parser_test_stmt(m); @@ -3191,50 +3291,50 @@ static ast_stmt_t *parser_global_stmt(module_t *m) { } static parser_rule rules[] = { - [TOKEN_LEFT_PAREN] = {parser_left_paren_expr, parser_call_expr, PRECEDENCE_CALL}, - [TOKEN_LEFT_SQUARE] = {parser_left_square_expr, parser_access, PRECEDENCE_SELECT}, - [TOKEN_LEFT_CURLY] = {parser_left_curly_expr, NULL, PRECEDENCE_NULL}, - [TOKEN_LESS_THAN] = {NULL, parser_binary, PRECEDENCE_COMPARE}, - [TOKEN_LEFT_ANGLE] = {NULL, parser_type_args_expr, PRECEDENCE_SELECT}, - [TOKEN_MACRO_IDENT] = {parser_macro_call, NULL, PRECEDENCE_NULL}, - [TOKEN_DOT] = {NULL, parser_unknown_select, PRECEDENCE_SELECT}, - [TOKEN_MINUS] = {parser_unary, parser_binary, PRECEDENCE_TERM}, - [TOKEN_PLUS] = {NULL, parser_binary, PRECEDENCE_TERM}, - [TOKEN_NOT] = {parser_unary, NULL, PRECEDENCE_UNARY}, - [TOKEN_TILDE] = {parser_unary, NULL, PRECEDENCE_UNARY}, - [TOKEN_AND] = {parser_unary, parser_binary, PRECEDENCE_AND}, - [TOKEN_OR] = {NULL, parser_binary, PRECEDENCE_OR}, - [TOKEN_XOR] = {NULL, parser_binary, PRECEDENCE_XOR}, - [TOKEN_LEFT_SHIFT] = {NULL, parser_binary, PRECEDENCE_SHIFT}, - [TOKEN_PERSON] = {NULL, parser_binary, PRECEDENCE_FACTOR}, - [TOKEN_STAR] = {parser_unary, parser_binary, PRECEDENCE_FACTOR}, - [TOKEN_SLASH] = {NULL, parser_binary, PRECEDENCE_FACTOR}, - [TOKEN_OR_OR] = {NULL, parser_binary, PRECEDENCE_OR_OR}, - [TOKEN_AND_AND] = {NULL, parser_binary, PRECEDENCE_AND_AND}, - [TOKEN_NOT_EQUAL] = {NULL, parser_binary, PRECEDENCE_CMP_EQUAL}, - [TOKEN_EQUAL_EQUAL] = {NULL, parser_binary, PRECEDENCE_CMP_EQUAL}, - - [TOKEN_RIGHT_SHIFT] = {NULL, parser_binary, PRECEDENCE_SHIFT}, - [TOKEN_RIGHT_ANGLE] = {NULL, parser_binary, PRECEDENCE_COMPARE}, - - [TOKEN_GREATER_EQUAL] = {NULL, parser_binary, PRECEDENCE_COMPARE}, - [TOKEN_LESS_EQUAL] = {NULL, parser_binary, PRECEDENCE_COMPARE}, - [TOKEN_LITERAL_STRING] = {parser_literal, NULL, PRECEDENCE_NULL}, - [TOKEN_LITERAL_INT] = {parser_literal, NULL, PRECEDENCE_NULL}, - [TOKEN_LITERAL_FLOAT] = {parser_literal, NULL, PRECEDENCE_NULL}, - [TOKEN_TRUE] = {parser_literal, NULL, PRECEDENCE_NULL}, - [TOKEN_FALSE] = {parser_literal, NULL, PRECEDENCE_NULL}, - [TOKEN_NULL] = {parser_literal, NULL, PRECEDENCE_NULL}, - - [TOKEN_AS] = {NULL, parser_as_expr, PRECEDENCE_TYPE_CAST}, - [TOKEN_IS] = {parser_match_is_expr, parser_is_expr, PRECEDENCE_TYPE_CAST}, - [TOKEN_CATCH] = {NULL, parser_catch_expr, PRECEDENCE_CATCH}, - [TOKEN_QUESTION] = {NULL, parser_ternary, PRECEDENCE_TERNARY}, - - // 以 ident 开头的前缀表达式 - [TOKEN_IDENT] = {parser_ident_expr, NULL, PRECEDENCE_NULL}, - [TOKEN_CHAN] = {parser_ident_expr, NULL, PRECEDENCE_NULL}, - [TOKEN_EOF] = {NULL, NULL, PRECEDENCE_NULL}, + [TOKEN_LEFT_PAREN] = {parser_left_paren_expr, parser_call_expr, PRECEDENCE_CALL}, + [TOKEN_LEFT_SQUARE] = {parser_left_square_expr, parser_access, PRECEDENCE_SELECT}, + [TOKEN_LEFT_CURLY] = {parser_left_curly_expr, NULL, PRECEDENCE_NULL}, + [TOKEN_LESS_THAN] = {NULL, parser_binary, PRECEDENCE_COMPARE}, + [TOKEN_LEFT_ANGLE] = {NULL, parser_type_args_expr, PRECEDENCE_SELECT}, + [TOKEN_MACRO_IDENT] = {parser_macro_call, NULL, PRECEDENCE_NULL}, + [TOKEN_DOT] = {NULL, parser_unknown_select, PRECEDENCE_SELECT}, + [TOKEN_MINUS] = {parser_unary, parser_binary, PRECEDENCE_TERM}, + [TOKEN_PLUS] = {NULL, parser_binary, PRECEDENCE_TERM}, + [TOKEN_NOT] = {parser_unary, NULL, PRECEDENCE_UNARY}, + [TOKEN_TILDE] = {parser_unary, NULL, PRECEDENCE_UNARY}, + [TOKEN_AND] = {parser_unary, parser_binary, PRECEDENCE_AND}, + [TOKEN_OR] = {NULL, parser_binary, PRECEDENCE_OR}, + [TOKEN_XOR] = {NULL, parser_binary, PRECEDENCE_XOR}, + [TOKEN_LEFT_SHIFT] = {NULL, parser_binary, PRECEDENCE_SHIFT}, + [TOKEN_PERSON] = {NULL, parser_binary, PRECEDENCE_FACTOR}, + [TOKEN_STAR] = {parser_unary, parser_binary, PRECEDENCE_FACTOR}, + [TOKEN_SLASH] = {NULL, parser_binary, PRECEDENCE_FACTOR}, + [TOKEN_OR_OR] = {NULL, parser_binary, PRECEDENCE_OR_OR}, + [TOKEN_AND_AND] = {NULL, parser_binary, PRECEDENCE_AND_AND}, + [TOKEN_NOT_EQUAL] = {NULL, parser_binary, PRECEDENCE_CMP_EQUAL}, + [TOKEN_EQUAL_EQUAL] = {NULL, parser_binary, PRECEDENCE_CMP_EQUAL}, + + [TOKEN_RIGHT_SHIFT] = {NULL, parser_binary, PRECEDENCE_SHIFT}, + [TOKEN_RIGHT_ANGLE] = {NULL, parser_binary, PRECEDENCE_COMPARE}, + + [TOKEN_GREATER_EQUAL] = {NULL, parser_binary, PRECEDENCE_COMPARE}, + [TOKEN_LESS_EQUAL] = {NULL, parser_binary, PRECEDENCE_COMPARE}, + [TOKEN_LITERAL_STRING] = {parser_literal, NULL, PRECEDENCE_NULL}, + [TOKEN_LITERAL_INT] = {parser_literal, NULL, PRECEDENCE_NULL}, + [TOKEN_LITERAL_FLOAT] = {parser_literal, NULL, PRECEDENCE_NULL}, + [TOKEN_TRUE] = {parser_literal, NULL, PRECEDENCE_NULL}, + [TOKEN_FALSE] = {parser_literal, NULL, PRECEDENCE_NULL}, + [TOKEN_NULL] = {parser_literal, NULL, PRECEDENCE_NULL}, + + [TOKEN_AS] = {NULL, parser_as_expr, PRECEDENCE_TYPE_CAST}, + [TOKEN_IS] = {parser_match_is_expr, parser_is_expr, PRECEDENCE_TYPE_CAST}, + [TOKEN_CATCH] = {NULL, parser_catch_expr, PRECEDENCE_CATCH}, + [TOKEN_QUESTION] = {NULL, parser_ternary, PRECEDENCE_TERNARY}, + + // 以 ident 开头的前缀表达式 + [TOKEN_IDENT] = {parser_ident_expr, NULL, PRECEDENCE_NULL}, + [TOKEN_CHAN] = {parser_ident_expr, NULL, PRECEDENCE_NULL}, + [TOKEN_EOF] = {NULL, NULL, PRECEDENCE_NULL}, }; /** @@ -3759,7 +3859,7 @@ static ast_expr_t parser_expr(module_t *m) { } // fn def, 也能写到括号里面呀 - if (parser_is(m, TOKEN_FN)) { + if (parser_is(m, TOKEN_FN) || parser_is(m, TOKEN_FX)) { return parser_fndef_expr(m); } diff --git a/src/syntax/scanner.c b/src/syntax/scanner.c index 5597f6d5..12ceb128 100644 --- a/src/syntax/scanner.c +++ b/src/syntax/scanner.c @@ -752,6 +752,12 @@ static token_type_t scanner_ident(char *word, int length) { return scanner_rest(word, length, 2, 2, "an", TOKEN_CHAN); } break; + case 'd': + switch (word[1]) { + case 'e': + return scanner_rest(word, length, 2, 3, "fer", TOKEN_DEFER); + } + break; case 'e': switch (word[1]) { case 'l': @@ -764,6 +770,8 @@ static token_type_t scanner_ident(char *word, int length) { switch (word[1]) { case 'n': return scanner_rest(word, length, 2, 0, "", TOKEN_FN); + case 'x': + return scanner_rest(word, length, 2, 0, "", TOKEN_FX); case 'a': return scanner_rest(word, length, 2, 3, "lse", TOKEN_FALSE); case 'l': diff --git a/src/syntax/token.h b/src/syntax/token.h index f6f6b77c..ae150d62 100644 --- a/src/syntax/token.h +++ b/src/syntax/token.h @@ -22,7 +22,7 @@ typedef enum { TOKEN_MINUS, // - TOKEN_PLUS, // + TOKEN_ELLIPSIS, // ... - TOKEN_RANGE, // ... + TOKEN_RANGE, // .. TOKEN_COLON, // : TOKEN_SEMICOLON, // ; TOKEN_SLASH, // / @@ -129,8 +129,10 @@ typedef enum { TOKEN_AS, TOKEN_BOOM, TOKEN_FN, + TOKEN_FX, TOKEN_IMPORT, TOKEN_RETURN, + TOKEN_DEFER, TOKEN_GO, TOKEN_STMT_EOF, // ; TOKEN_EOF,// TOKEN_EOF 一定要在最后一个,否则会索引溢出 @@ -235,7 +237,9 @@ static string token_str[] = { [TOKEN_U64] = "u64", [TOKEN_FN] = "fn", + [TOKEN_FX] = "fx", [TOKEN_RETURN] = "return", + [TOKEN_DEFER] = "defer", [TOKEN_CATCH] = "catch", [TOKEN_MATCH] = "match", [TOKEN_SELECT] = "select", diff --git a/src/types.h b/src/types.h index fd5278bf..82a2aa9d 100644 --- a/src/types.h +++ b/src/types.h @@ -195,6 +195,9 @@ struct module_t { bool parser_match_cond; bool parser_match_subject; // 是否包含 subject + // analyzer defer 语义检查,>0 表示当前位于 defer block 内 + int64_t in_defer_block_depth; + /** * analyzer 时判断 expr 是否存在 fndef @@ -548,6 +551,7 @@ typedef struct closure_t { ct_stack_t *break_labels; // 用于 for break lir_operand* ct_stack_t *ret_targets; // default type_unknown ct_stack_t *ret_labels; // default type_unknown + ct_stack_t *defer_scopes; // linear_defer_scope_t* // lir_operand_t, 大返回值引导 void *return_big_operand; @@ -586,6 +590,7 @@ typedef struct closure_t { bool exists_call; bool exists_sp; + bool is_fx; slice_t *callee_saved; // 记录函数中使用的 callee-saved 寄存器 (reg_t*) diff --git a/std/allocator/arena.n b/std/allocator/arena.n new file mode 100644 index 00000000..34d7734d --- /dev/null +++ b/std/allocator/arena.n @@ -0,0 +1,178 @@ +import allocator.types.{allocatable} +import libc + +int ALIGN = 8 // default alignment (8 bytes, suitable for most types) + +// arena block, each block is a contiguous chunk of memory +type block_t = struct{ + ptr next // next block in linked list + int capacity // total capacity of this block (bytes) + int used // bytes already used +} + +type arena_t:allocatable = struct{ + ptr head // first block in linked list + ptr current // current active block for allocation + int block_size // default capacity for new blocks + anyptr last_alloc // pointer to the last allocation (for tail-free optimization) + int last_alloc_size // size of the last allocation +} + +// align offset up to the nearest multiple of ALIGN +fx align_up(int offset):int { + return (offset + ALIGN - 1) & ~(ALIGN - 1) +} + +// allocate a new block with the given capacity +fx block_new(int capacity):ptr { + // allocate memory for block header + data area + int total = @sizeof(block_t) + capacity + ptr b = libc.malloc(total as u64) as ptr + if b == null { + panic('arena: block_new malloc failed') + } + + b.next = null + b.capacity = capacity + b.used = 0 + return b +} + +// get the data area start address of a block +fx block_data(ptr b):anyptr { + // data starts right after the block_t header + return b as anyptr + @sizeof(block_t) +} + +// try to allocate size bytes from a block with alignment, returns null on failure +fx block_alloc(ptr b, int size):anyptr { + // align the current used offset + int aligned_used = align_up(b.used) + + if aligned_used + size > b.capacity { + return null + } + + anyptr p = (block_data(b) as int + aligned_used) as anyptr + b.used = aligned_used + size + return p +} + +fx init(int capacity):ptr { + ptr a = libc.malloc(@sizeof(arena_t)) as ptr + if a == null { + panic('arena: init malloc failed') + } + + // ensure minimum block size + int block_size = capacity + if block_size <= 0 { + block_size = 4096 + } + + var first_block = block_new(block_size) + a.head = first_block + a.current = first_block + a.block_size = block_size + a.last_alloc = null + a.last_alloc_size = 0 + + return a +} + +fx arena_t.deinit(*self) { + // walk the linked list and free all blocks + var b = self.head + for b != null { + var next = b.next + libc.free(b as anyptr) + b = next + } + + // free the arena struct itself + libc.free(self as anyptr) +} + +// allocatable interface impl: allocate `size` bytes from the arena +fx arena_t.alloc(*self, int size):anyptr { + if size <= 0 { + panic('arena: alloc invalid size') + } + + // try to allocate from current block (with alignment) + anyptr p = block_alloc(self.current, size) + + // if current block is full, allocate a new block + if p == null { + // new block must be at least large enough for this allocation + int new_cap = self.block_size + if size > new_cap { + new_cap = size + } + + var new_block = block_new(new_cap) + self.current.next = new_block + self.current = new_block + p = block_alloc(new_block, size) + if p == null { + panic('arena: alloc failed after expanding') + } + } + + // record last allocation for tail-free optimization + self.last_alloc = p + self.last_alloc_size = size + + return p +} + +// allocatable interface impl: deallocate memory at `p` +// arena only supports tail-free optimization +fx arena_t.dealloc(*self, anyptr p) { + // tail-free optimization: if freeing the most recent allocation, + // rewind the current block's used pointer + if p == self.last_alloc { + self.current.used -= self.last_alloc_size + self.last_alloc = null + self.last_alloc_size = 0 + } + // otherwise no-op — arena does not support freeing arbitrary allocations +} + +// convenience generic helper: allocate and initialize a value of type T +fx arena_t.new(*self, T value):ptr { + int size = @sizeof(T) + if size <= 0 { + panic('arena: new invalid type size') + } + + anyptr p = self.alloc(size) + + // copy value into the allocated memory + libc.memmove(p, &value as anyptr, size as u64) + return p as ptr +} + +// convenience generic helper: free a typed pointer +fx arena_t.free(*self, ptr p) { + self.dealloc(p as anyptr) +} + +fx arena_t.reset(*self) { + // free all blocks except the first one to release excess memory + var b = self.head.next + for b != null { + var next = b.next + libc.free(b as anyptr) + b = next + } + + // keep only the first block and reset it + self.head.next = null + self.head.used = 0 + self.current = self.head + + // clear tail-free state + self.last_alloc = null + self.last_alloc_size = 0 +} \ No newline at end of file diff --git a/std/allocator/main.n b/std/allocator/main.n new file mode 100644 index 00000000..928157ec --- /dev/null +++ b/std/allocator/main.n @@ -0,0 +1,51 @@ +import libc +import allocator.types.{allocatable} + +type heap_t:allocatable = int + +heap_t heap = 0 + +// allocatable interface impl: allocate `size` bytes from the heap +fx heap_t.alloc(*self, int size):anyptr { + var p = libc.malloc(size as u64) + if p == null { + panic('allocator.alloc failed') + } + + libc.memset(p as anyptr, 0, size as u64) + return p +} + +// allocatable interface impl: deallocate memory at `p` +fx heap_t.dealloc(*self, anyptr p) { + if p == null { + return + } + + libc.free(p) +} + +// convenience generic helper: allocate and initialize a value of type T +fx heap_t.new(*self, T value):ptr { + int size = @sizeof(T) + if size <= 0 { + panic('allocator.new invalid type size') + } + + ptr p = self.alloc(size) as ptr + libc.memmove(p as anyptr, &value as anyptr, size as u64) + return p +} + +// convenience generic helper: free a typed pointer +fx heap_t.free(*self, ptr p) { + self.dealloc(p as anyptr) +} + +fx new(T value):ptr { + return heap.new(value) +} + +fx free(ptr p) { + return heap.free(p) +} diff --git a/std/allocator/package.toml b/std/allocator/package.toml new file mode 100644 index 00000000..edfd5da4 --- /dev/null +++ b/std/allocator/package.toml @@ -0,0 +1,7 @@ +name = "allocator" +version = "0.1.0" +authors = ["weiwenhao "] +license = "MIT" +type = "lib" + +[dependencies] diff --git a/std/allocator/types.n b/std/allocator/types.n new file mode 100644 index 00000000..791c18d9 --- /dev/null +++ b/std/allocator/types.n @@ -0,0 +1,4 @@ +type allocatable = interface{ + fx alloc(int size):anyptr + fx dealloc(anyptr p):void +} \ No newline at end of file diff --git a/std/builtin/builtin.n b/std/builtin/builtin.n index ff185fe1..d687a8b1 100644 --- a/std/builtin/builtin.n +++ b/std/builtin/builtin.n @@ -1,21 +1,13 @@ -// type fn_t = anyptr - -// type all_t = anyptr - -// type integer_t = int - -// type floater_t = float - type nullable = T? #linkid print -fn print(...[any] args) +fx print(...[any] args) #linkid println -fn println(...[any] args) +fx println(...[any] args) #linkid rt_panic -fn panic(string msg) +fx panic(string msg) #linkid rt_assert -fn assert(bool cond) \ No newline at end of file +fx assert(bool cond) \ No newline at end of file diff --git a/std/builtin/error.n b/std/builtin/error.n index 9174acfc..f9aa5d65 100644 --- a/std/builtin/error.n +++ b/std/builtin/error.n @@ -4,6 +4,13 @@ type throwable = interface{ fn msg():string } +type trace_t = struct{ + string path + string ident + int line + int column +} + type errort:throwable = struct{ string message bool is_panic diff --git a/std/builtin/vec.n b/std/builtin/vec.n index 777ad099..552ba6f3 100644 --- a/std/builtin/vec.n +++ b/std/builtin/vec.n @@ -1,14 +1,51 @@ import runtime +import allocator.types.{allocatable} +import allocator as ac +import reflect.{vec_t} +import libc -fn vec.new(T value, int len):vec { +const VEC_DEFAULT_CAPACITY = 8 + +fn vec.new(T default_value, int len):vec { int hash = @reflect_hash(vec) int element_hash = @reflect_hash(T) - return runtime.vec_new(hash, element_hash, len, &value as anyptr) catch e { + return runtime.vec_new(hash, element_hash, len, &default_value as anyptr) catch e { panic(e.msg()) [] } } +fx vec.alloc(allocatable a, T default_value, int len):vec { + if len < 0 { + panic('len must be greater than 0') + } + + int cap = len + + var ap = ac.new(a) + + var temp = vec_t{ + data: 0, + length: len, + capacity: cap, + element_size: @sizeof(T), + hash: @reflect_hash(T), + allocator: ap as anyptr, + } + + if len == 0 { + return temp as anyptr as vec + } + + temp.data = a.alloc(len * @sizeof(T)) + var result = temp as anyptr as vec + for i in 0..len { + result[i] = default_value + } + + return result +} + fn vec.cap_of(int cap):vec { int hash = @reflect_hash(vec) int element_hash = @reflect_hash(T) @@ -18,10 +55,55 @@ fn vec.cap_of(int cap):vec { } } -fn vec.push(*self, T v) { - ptr ref = &v - int element_hash = @reflect_hash(T) - return runtime.vec_push(self as anyptr, element_hash, ref as anyptr) +fx vec.grow(*self) { + ptr rv = self as anyptr as ptr + assert(rv.allocator > 0) + + if rv.capacity > 0 { + rv.capacity *= 2 + } else { + rv.capacity = VEC_DEFAULT_CAPACITY + } + + anyptr old_data = rv.data + allocatable a = *(rv.allocator as ptr) + rv.data = a.alloc(rv.capacity * @sizeof(T)) + + if rv.length > 0 { + libc.memmove(rv.data, old_data, rv.length as u64 * @sizeof(T)) + } + a.dealloc(old_data) +} + +fx vec.push(*self, T v) { + ptr rv = self as anyptr as ptr + if rv.allocator == 0 { + ptr ref = &v + int element_hash = @reflect_hash(T) + return runtime.vec_push(self as anyptr, element_hash, ref as anyptr) + } + + if rv.length == rv.capacity { + self.grow() + } + + // check index and assign + var index = rv.length + rv.length += 1 + var offset = (@sizeof(T) * index) as anyptr + anyptr p = rv.data + offset + libc.memmove(p, &v as anyptr, @sizeof(T)) +} + +fx vec.deinit(*self) { + ptr rv = self as anyptr as ptr + if rv.allocator == 0 { + return + } + + allocatable a = *(rv.allocator as ptr) + a.dealloc(rv.allocator) + a.dealloc(rv.data) } fn vec.append(*self, vec l2) { @@ -44,11 +126,15 @@ fn vec.concat(*self, vec l2):vec { #linkid rt_vec_copy fn vec.copy(*self, vec src):int -#linkid rt_vec_length -fn vec.len(*self):int +fx vec.len(*self):int { + var rv = self as anyptr as ptr + return rv.length +} -#linkid rt_vec_capacity -fn vec.cap(*self):int +fx vec.cap(*self):int { + var rv = self as anyptr as ptr + return rv.capacity +} #linkid rt_vec_ref fn vec.ref(*self):anyptr diff --git a/std/libc/main.n b/std/libc/main.n index a0bf3521..cf6a0322 100644 --- a/std/libc/main.n +++ b/std/libc/main.n @@ -1,9 +1,9 @@ type cstr = anyptr #linkid rt_string_ref -fn string.to_cstr(*self):cstr +fx string.to_cstr(*self):cstr -fn to_cfn(anyptr closure):anyptr { +fx to_cfn(anyptr closure):anyptr { type fn_t = struct{ anyptr envs anyptr addr @@ -17,80 +17,80 @@ const AF_INET = 2 const AF_INET6 = 10 #linkid rt_string_new -fn cstr.to_string(self):string +fx cstr.to_string(self):string // stdlib.h #linkid atoi -fn atoi(cstr str):i32 +fx atoi(cstr str):i32 #linkid atol -fn atol(cstr str):i64 +fx atol(cstr str):i64 #linkid atof -fn atof(cstr str):f64 +fx atof(cstr str):f64 #linkid strtof -fn strtof(cstr str, anyptr endptr):f32 +fx strtof(cstr str, anyptr endptr):f32 #linkid strtod -fn strtod(cstr str, anyptr endptr):f64 +fx strtod(cstr str, anyptr endptr):f64 #linkid strtol -fn strtol(cstr str, anyptr endptr, i32 base):i64 +fx strtol(cstr str, anyptr endptr, i32 base):i64 #linkid strtoul -fn strtoul(cstr str, anyptr endptr, i32 base):u64 +fx strtoul(cstr str, anyptr endptr, i32 base):u64 #linkid rand -fn rand():i32 +fx rand():i32 #linkid srand -fn srand(u32 seed):void +fx srand(u32 seed):void #linkid malloc -fn malloc(u64 size):anyptr +fx malloc(u64 size):anyptr #linkid calloc -fn calloc(u64 nmemb, u64 size):anyptr +fx calloc(u64 nmemb, u64 size):anyptr #linkid realloc -fn realloc(anyptr p, u64 size):anyptr +fx realloc(anyptr p, u64 size):anyptr #linkid free -fn free(anyptr p):void +fx free(anyptr p):void #linkid aligned_alloc -fn aligned_alloc(u64 alignment, u64 size):anyptr +fx aligned_alloc(u64 alignment, u64 size):anyptr #linkid abort -fn abort() +fx abort() #linkid atexit -fn atexit(anyptr func):i32 +fx atexit(anyptr func):i32 #linkid exit -fn exit(i32 status) +fx exit(i32 status) #linkid _Exit -fn _exit(i32 status) +fx _exit(i32 status) #linkid at_quick_exit -fn at_quick_exit(anyptr func):i32 +fx at_quick_exit(anyptr func):i32 #linkid quick_exit -fn quick_exit(i32 status) +fx quick_exit(i32 status) #linkid getenv -fn getenv(cstr name):cstr +fx getenv(cstr name):cstr #linkid system -fn system(cstr command):i32 +fx system(cstr command):i32 #linkid abs -fn abs(i32 x):i32 +fx abs(i32 x):i32 #linkid labs -fn labs(i64 x):i64 +fx labs(i64 x):i64 type div_t = struct { i32 quot @@ -103,148 +103,148 @@ type ldiv_t = struct { } #linkid div -fn div(i32 numer, i32 denom):div_t +fx div(i32 numer, i32 denom):div_t #linkid ldiv -fn ldiv(i64 numer, i64 denom):ldiv_t +fx ldiv(i64 numer, i64 denom):ldiv_t #linkid mblen -fn mblen(cstr s, u64 n):i32 +fx mblen(cstr s, u64 n):i32 #linkid mbtowc -fn mbtowc(anyptr pwc, cstr s, u64 n):i32 +fx mbtowc(anyptr pwc, cstr s, u64 n):i32 #linkid wctomb -fn wctomb(cstr s, i32 wc):i32 +fx wctomb(cstr s, i32 wc):i32 #linkid mbstowcs -fn mbstowcs(anyptr pwcs, cstr s, u64 n):u64 +fx mbstowcs(anyptr pwcs, cstr s, u64 n):u64 #linkid wcstombs -fn wcstombs(cstr s, anyptr pwcs, u64 n):u64 +fx wcstombs(cstr s, anyptr pwcs, u64 n):u64 #linkid posix_memalign -fn posix_memalign(anyptr memptr, u64 alignment, u64 size):i32 +fx posix_memalign(anyptr memptr, u64 alignment, u64 size):i32 #linkid setenv -fn setenv(cstr name, cstr value, i32 overwrite):i32 +fx setenv(cstr name, cstr value, i32 overwrite):i32 #linkid unsetenv -fn unsetenv(cstr name):i32 +fx unsetenv(cstr name):i32 #linkid putenv -fn putenv(cstr str):i32 +fx putenv(cstr str):i32 #linkid mkstemp -fn mkstemp(cstr template):i32 +fx mkstemp(cstr template):i32 #linkid mkostemp -fn mkostemp(cstr template, i32 flags):i32 +fx mkostemp(cstr template, i32 flags):i32 #linkid mkdtemp -fn mkdtemp(cstr template):cstr +fx mkdtemp(cstr template):cstr #linkid mktemp -fn mktemp(cstr template):cstr +fx mktemp(cstr template):cstr #linkid mkstemps -fn mkstemps(cstr template, i32 suffixlen):i32 +fx mkstemps(cstr template, i32 suffixlen):i32 #linkid mkostemps -fn mkostemps(cstr template, i32 suffixlen, i32 flags):i32 +fx mkostemps(cstr template, i32 suffixlen, i32 flags):i32 #linkid getsubopt -fn getsubopt(anyptr optionp, anyptr tokens, anyptr valuep):i32 +fx getsubopt(anyptr optionp, anyptr tokens, anyptr valuep):i32 #linkid rand_r -fn rand_r(ptr seed):i32 +fx rand_r(ptr seed):i32 #linkid realpath -fn realpath(cstr path, cstr resolved_path):cstr +fx realpath(cstr path, cstr resolved_path):cstr #linkid random -fn random():i64 +fx random():i64 #linkid srandom -fn srandom(u32 seed):void +fx srandom(u32 seed):void #linkid initstate -fn initstate(u32 seed, cstr state, u64 size):cstr +fx initstate(u32 seed, cstr state, u64 size):cstr #linkid setstate -fn setstate(cstr state):cstr +fx setstate(cstr state):cstr #linkid posix_openpt -fn posix_openpt(i32 flags):i32 +fx posix_openpt(i32 flags):i32 #linkid grantpt -fn grantpt(i32 fd):i32 +fx grantpt(i32 fd):i32 #linkid unlockpt -fn unlockpt(i32 fd):i32 +fx unlockpt(i32 fd):i32 #linkid ptsname_r -fn ptsname_r(i32 fd, cstr buf, u64 buflen):i32 +fx ptsname_r(i32 fd, cstr buf, u64 buflen):i32 #linkid l64a -fn l64a(i64 value):cstr +fx l64a(i64 value):cstr #linkid a64l -fn a64l(cstr s):i64 +fx a64l(cstr s):i64 #linkid setkey -fn setkey(cstr key):void +fx setkey(cstr key):void #linkid drand48 -fn drand48():f64 +fx drand48():f64 #linkid erand48 -fn erand48(anyptr xsubi):f64 +fx erand48(anyptr xsubi):f64 #linkid lrand48 -fn lrand48():i64 +fx lrand48():i64 #linkid nrand48 -fn nrand48(anyptr xsubi):i64 +fx nrand48(anyptr xsubi):i64 #linkid mrand48 -fn mrand48():i64 +fx mrand48():i64 #linkid jrand48 -fn jrand48(anyptr xsubi):i64 +fx jrand48(anyptr xsubi):i64 #linkid srand48 -fn srand48(i64 seedval):void +fx srand48(i64 seedval):void #linkid seed48 -fn seed48(anyptr seed16v):ptr +fx seed48(anyptr seed16v):ptr #linkid lcong48 -fn lcong48(anyptr param):void +fx lcong48(anyptr param):void #linkid valloc -fn valloc(u64 size):anyptr +fx valloc(u64 size):anyptr #linkid memalign -fn memalign(u64 alignment, u64 size):anyptr +fx memalign(u64 alignment, u64 size):anyptr #linkid reallocarray -fn reallocarray(anyptr p, u64 nmemb, u64 size):anyptr +fx reallocarray(anyptr p, u64 nmemb, u64 size):anyptr #linkid getloadavg -fn getloadavg(ptr loadavg, i32 nelem):i32 +fx getloadavg(ptr loadavg, i32 nelem):i32 #linkid ecvt -fn ecvt(f64 number, i32 ndigits, ptr decpt, ptr sign):cstr +fx ecvt(f64 number, i32 ndigits, ptr decpt, ptr sign):cstr #linkid fcvt -fn fcvt(f64 number, i32 ndigits, ptr decpt, ptr sign):cstr +fx fcvt(f64 number, i32 ndigits, ptr decpt, ptr sign):cstr #linkid gcvt -fn gcvt(f64 number, i32 ndigit, cstr buf):cstr +fx gcvt(f64 number, i32 ndigit, cstr buf):cstr #linkid secure_getenv -fn secure_getenv(cstr name):cstr +fx secure_getenv(cstr name):cstr // stdio.h @@ -274,214 +274,214 @@ type fpos_t = struct { } #linkid fopen -fn fopen(cstr filename, cstr mode):fileptr +fx fopen(cstr filename, cstr mode):fileptr #linkid freopen -fn freopen(cstr filename, cstr mode, fileptr stream):fileptr +fx freopen(cstr filename, cstr mode, fileptr stream):fileptr #linkid fclose -fn fclose(fileptr stream):i32 +fx fclose(fileptr stream):i32 #linkid remove -fn remove(cstr filename):i32 +fx remove(cstr filename):i32 #linkid rename -fn rename(cstr old_name, cstr new_name):i32 +fx rename(cstr old_name, cstr new_name):i32 #linkid feof -fn feof(fileptr stream):i32 +fx feof(fileptr stream):i32 #linkid ferror -fn ferror(fileptr stream):i32 +fx ferror(fileptr stream):i32 #linkid fflush -fn fflush(fileptr stream):i32 +fx fflush(fileptr stream):i32 #linkid clearerr -fn clearerr(fileptr stream):void +fx clearerr(fileptr stream):void #linkid fseek -fn fseek(fileptr stream, i64 offset, i32 whence):i32 +fx fseek(fileptr stream, i64 offset, i32 whence):i32 #linkid ftell -fn ftell(fileptr stream):i64 +fx ftell(fileptr stream):i64 #linkid rewind -fn rewind(fileptr stream):void +fx rewind(fileptr stream):void #linkid fgetpos -fn fgetpos(fileptr stream, ptr pos):i32 +fx fgetpos(fileptr stream, ptr pos):i32 #linkid fsetpos -fn fsetpos(fileptr stream, ptr pos):i32 +fx fsetpos(fileptr stream, ptr pos):i32 #linkid fread -fn fread(anyptr p, u64 size, u64 nmemb, fileptr stream):u64 +fx fread(anyptr p, u64 size, u64 nmemb, fileptr stream):u64 #linkid fwrite -fn fwrite(anyptr p, u64 size, u64 nmemb, fileptr stream):u64 +fx fwrite(anyptr p, u64 size, u64 nmemb, fileptr stream):u64 #linkid fgetc -fn fgetc(fileptr stream):i32 +fx fgetc(fileptr stream):i32 #linkid getc -fn getc(fileptr stream):i32 +fx getc(fileptr stream):i32 #linkid getchar -fn getchar():i32 +fx getchar():i32 #linkid ungetc -fn ungetc(i32 c, fileptr stream):i32 +fx ungetc(i32 c, fileptr stream):i32 #linkid fputc -fn fputc(i32 c, fileptr stream):i32 +fx fputc(i32 c, fileptr stream):i32 #linkid putc -fn putc(i32 c, fileptr stream):i32 +fx putc(i32 c, fileptr stream):i32 #linkid putchar -fn putchar(i32 c):i32 +fx putchar(i32 c):i32 #linkid fgets -fn fgets(cstr s, i32 size, fileptr stream):cstr +fx fgets(cstr s, i32 size, fileptr stream):cstr #linkid fputs -fn fputs(cstr s, fileptr stream):i32 +fx fputs(cstr s, fileptr stream):i32 #linkid puts -fn puts(cstr s):i32 +fx puts(cstr s):i32 // Error handling #linkid perror -fn perror(cstr s):void +fx perror(cstr s):void // Buffer control #linkid setvbuf -fn setvbuf(fileptr stream, cstr buffer, i32 mode, u64 size):i32 +fx setvbuf(fileptr stream, cstr buffer, i32 mode, u64 size):i32 #linkid setbuf -fn setbuf(fileptr stream, cstr buffer):void +fx setbuf(fileptr stream, cstr buffer):void // Temporary files #linkid tmpnam -fn tmpnam(cstr s):cstr +fx tmpnam(cstr s):cstr #linkid tmpfile -fn tmpfile():fileptr +fx tmpfile():fileptr // POSIX extensions #linkid fmemopen -fn fmemopen(anyptr buffer, u64 size, cstr mode):fileptr +fx fmemopen(anyptr buffer, u64 size, cstr mode):fileptr #linkid open_memstream -fn open_memstream(ptr bufp, ptr sizep):fileptr +fx open_memstream(ptr bufp, ptr sizep):fileptr #linkid fdopen -fn fdopen(i32 fd, cstr mode):fileptr +fx fdopen(i32 fd, cstr mode):fileptr #linkid popen -fn popen(cstr command, cstr t):fileptr +fx popen(cstr command, cstr t):fileptr #linkid pclose -fn pclose(fileptr stream):i32 +fx pclose(fileptr stream):i32 #linkid fileno -fn fileno(fileptr stream):i32 +fx fileno(fileptr stream):i32 #linkid fseeko -fn fseeko(fileptr stream, i64 offset, i32 whence):i32 +fx fseeko(fileptr stream, i64 offset, i32 whence):i32 #linkid ftello -fn ftello(fileptr stream):i64 +fx ftello(fileptr stream):i64 // File locking #linkid flockfile -fn flockfile(fileptr stream):void +fx flockfile(fileptr stream):void #linkid ftrylockfile -fn ftrylockfile(fileptr stream):i32 +fx ftrylockfile(fileptr stream):i32 #linkid funlockfile -fn funlockfile(fileptr stream):void +fx funlockfile(fileptr stream):void // Unlocked I/O #linkid getc_unlocked -fn getc_unlocked(fileptr stream):i32 +fx getc_unlocked(fileptr stream):i32 #linkid getchar_unlocked -fn getchar_unlocked():i32 +fx getchar_unlocked():i32 #linkid putc_unlocked -fn putc_unlocked(i32 c, fileptr stream):i32 +fx putc_unlocked(i32 c, fileptr stream):i32 #linkid putchar_unlocked -fn putchar_unlocked(i32 c):i32 +fx putchar_unlocked(i32 c):i32 #linkid fgetc_unlocked -fn fgetc_unlocked(fileptr stream):i32 +fx fgetc_unlocked(fileptr stream):i32 #linkid fputc_unlocked -fn fputc_unlocked(i32 c, fileptr stream):i32 +fx fputc_unlocked(i32 c, fileptr stream):i32 #linkid fflush_unlocked -fn fflush_unlocked(fileptr stream):i32 +fx fflush_unlocked(fileptr stream):i32 #linkid fread_unlocked -fn fread_unlocked(anyptr p, u64 size, u64 nmemb, fileptr stream):u64 +fx fread_unlocked(anyptr p, u64 size, u64 nmemb, fileptr stream):u64 #linkid fwrite_unlocked -fn fwrite_unlocked(anyptr p, u64 size, u64 nmemb, fileptr stream):u64 +fx fwrite_unlocked(anyptr p, u64 size, u64 nmemb, fileptr stream):u64 #linkid clearerr_unlocked -fn clearerr_unlocked(fileptr stream):void +fx clearerr_unlocked(fileptr stream):void #linkid feof_unlocked -fn feof_unlocked(fileptr stream):i32 +fx feof_unlocked(fileptr stream):i32 #linkid ferror_unlocked -fn ferror_unlocked(fileptr stream):i32 +fx ferror_unlocked(fileptr stream):i32 #linkid fileno_unlocked -fn fileno_unlocked(fileptr stream):i32 +fx fileno_unlocked(fileptr stream):i32 #linkid fgets_unlocked -fn fgets_unlocked(cstr s, i32 size, fileptr stream):cstr +fx fgets_unlocked(cstr s, i32 size, fileptr stream):cstr #linkid fputs_unlocked -fn fputs_unlocked(cstr s, fileptr stream):i32 +fx fputs_unlocked(cstr s, fileptr stream):i32 // Line-oriented I/O #linkid getdelim -fn getdelim(ptr lineptr, ptr n, i32 delim, fileptr stream):i64 +fx getdelim(ptr lineptr, ptr n, i32 delim, fileptr stream):i64 #linkid getline -fn getline(ptr lineptr, ptr n, fileptr stream):i64 +fx getline(ptr lineptr, ptr n, fileptr stream):i64 // Additional functions #linkid renameat -fn renameat(i32 olddirfd, cstr oldpath, i32 newdirfd, cstr newpath):i32 +fx renameat(i32 olddirfd, cstr oldpath, i32 newdirfd, cstr newpath):i32 #linkid tempnam -fn tempnam(cstr dir, cstr pfx):cstr +fx tempnam(cstr dir, cstr pfx):cstr #linkid cuserid -fn cuserid(cstr s):cstr +fx cuserid(cstr s):cstr #linkid setlinebuf -fn setlinebuf(fileptr stream):void +fx setlinebuf(fileptr stream):void #linkid setbuffer -fn setbuffer(fileptr stream, cstr buffer, u64 size):void +fx setbuffer(fileptr stream, cstr buffer, u64 size):void #linkid getw -fn getw(fileptr stream):i32 +fx getw(fileptr stream):i32 #linkid putw -fn putw(i32 w, fileptr stream):i32 +fx putw(i32 w, fileptr stream):i32 #linkid fgetln -fn fgetln(fileptr stream, ptr len):cstr +fx fgetln(fileptr stream, ptr len):cstr // Cookie I/O function types type cookie_read_function_t = fn(anyptr, cstr, u64):i64 @@ -497,159 +497,159 @@ type cookie_io_functions_t = struct { } #linkid fopencookie -fn fopencookie(anyptr cookie, cstr mode, cookie_io_functions_t io_funcs):fileptr +fx fopencookie(anyptr cookie, cstr mode, cookie_io_functions_t io_funcs):fileptr // string.h // Memory functions #linkid memcpy -fn memcpy(anyptr dst, anyptr src, u64 n):anyptr +fx memcpy(anyptr dst, anyptr src, u64 n):anyptr #linkid memmove -fn memmove(anyptr dst, anyptr src, u64 n):anyptr +fx memmove(anyptr dst, anyptr src, u64 n):anyptr #linkid memset -fn memset(anyptr s, i32 c, u64 n):anyptr +fx memset(anyptr s, i32 c, u64 n):anyptr #linkid memcmp -fn memcmp(anyptr s1, anyptr s2, u64 n):i32 +fx memcmp(anyptr s1, anyptr s2, u64 n):i32 #linkid memchr -fn memchr(anyptr s, i32 c, u64 n):anyptr +fx memchr(anyptr s, i32 c, u64 n):anyptr // String copy functions #linkid strcpy -fn strcpy(cstr dst, cstr src):cstr +fx strcpy(cstr dst, cstr src):cstr #linkid strncpy -fn strncpy(cstr dst, cstr src, u64 n):cstr +fx strncpy(cstr dst, cstr src, u64 n):cstr // String concatenation functions #linkid strcat -fn strcat(cstr dst, cstr src):cstr +fx strcat(cstr dst, cstr src):cstr #linkid strncat -fn strncat(cstr dst, cstr src, u64 n):cstr +fx strncat(cstr dst, cstr src, u64 n):cstr // String comparison functions #linkid strcmp -fn strcmp(cstr s1, cstr s2):i32 +fx strcmp(cstr s1, cstr s2):i32 #linkid strncmp -fn strncmp(cstr s1, cstr s2, u64 n):i32 +fx strncmp(cstr s1, cstr s2, u64 n):i32 #linkid strcoll -fn strcoll(cstr s1, cstr s2):i32 +fx strcoll(cstr s1, cstr s2):i32 #linkid strxfrm -fn strxfrm(cstr dst, cstr src, u64 n):u64 +fx strxfrm(cstr dst, cstr src, u64 n):u64 // String search functions #linkid strchr -fn strchr(cstr s, i32 c):cstr +fx strchr(cstr s, i32 c):cstr #linkid strrchr -fn strrchr(cstr s, i32 c):cstr +fx strrchr(cstr s, i32 c):cstr #linkid strcspn -fn strcspn(cstr s1, cstr s2):u64 +fx strcspn(cstr s1, cstr s2):u64 #linkid strspn -fn strspn(cstr s1, cstr s2):u64 +fx strspn(cstr s1, cstr s2):u64 #linkid strpbrk -fn strpbrk(cstr s1, cstr s2):cstr +fx strpbrk(cstr s1, cstr s2):cstr #linkid strstr -fn strstr(cstr haystack, cstr needle):cstr +fx strstr(cstr haystack, cstr needle):cstr #linkid strtok -fn strtok(cstr str, cstr delim):cstr +fx strtok(cstr str, cstr delim):cstr // String length function #linkid strlen -fn strlen(cstr s):u64 +fx strlen(cstr s):u64 #linkid rt_strerror -fn error_string():string +fx error_string():string // Error functions #linkid strerror -fn strerror(i32 errnum):cstr +fx strerror(i32 errnum):cstr // POSIX extensions #linkid strtok_r -fn strtok_r(cstr str, cstr delim, ptr saveptr):cstr +fx strtok_r(cstr str, cstr delim, ptr saveptr):cstr #linkid strerror_r -fn strerror_r(i32 errnum, cstr buf, u64 buflen):i32 +fx strerror_r(i32 errnum, cstr buf, u64 buflen):i32 #linkid stpcpy -fn stpcpy(cstr dst, cstr src):cstr +fx stpcpy(cstr dst, cstr src):cstr #linkid stpncpy -fn stpncpy(cstr dst, cstr src, u64 n):cstr +fx stpncpy(cstr dst, cstr src, u64 n):cstr #linkid strnlen -fn strnlen(cstr s, u64 maxlen):u64 +fx strnlen(cstr s, u64 maxlen):u64 #linkid strdup -fn strdup(cstr s):cstr +fx strdup(cstr s):cstr #linkid strndup -fn strndup(cstr s, u64 n):cstr +fx strndup(cstr s, u64 n):cstr #linkid strsignal -fn strsignal(i32 sig):cstr +fx strsignal(i32 sig):cstr // Locale-aware functions (requires locale_t type) type locale_t = anyptr #linkid strerror_l -fn strerror_l(i32 errnum, locale_t locale):cstr +fx strerror_l(i32 errnum, locale_t locale):cstr #linkid strcoll_l -fn strcoll_l(cstr s1, cstr s2, locale_t locale):i32 +fx strcoll_l(cstr s1, cstr s2, locale_t locale):i32 #linkid strxfrm_l -fn strxfrm_l(cstr dst, cstr src, u64 n, locale_t locale):u64 +fx strxfrm_l(cstr dst, cstr src, u64 n, locale_t locale):u64 #linkid memmem -fn memmem(anyptr haystack, u64 haystacklen, anyptr needle, u64 needlelen):anyptr +fx memmem(anyptr haystack, u64 haystacklen, anyptr needle, u64 needlelen):anyptr // X/Open extensions #linkid memccpy -fn memccpy(anyptr dst, anyptr src, i32 c, u64 n):anyptr +fx memccpy(anyptr dst, anyptr src, i32 c, u64 n):anyptr // GNU/BSD extensions #linkid strsep -fn strsep(ptr strp, cstr delim):cstr +fx strsep(ptr strp, cstr delim):cstr #linkid strlcat -fn strlcat(cstr dst, cstr src, u64 size):u64 +fx strlcat(cstr dst, cstr src, u64 size):u64 #linkid strlcpy -fn strlcpy(cstr dst, cstr src, u64 size):u64 +fx strlcpy(cstr dst, cstr src, u64 size):u64 #linkid explicit_bzero -fn explicit_bzero(anyptr s, u64 n):void +fx explicit_bzero(anyptr s, u64 n):void // GNU extensions #linkid strverscmp -fn strverscmp(cstr s1, cstr s2):i32 +fx strverscmp(cstr s1, cstr s2):i32 #linkid strchrnul -fn strchrnul(cstr s, i32 c):cstr +fx strchrnul(cstr s, i32 c):cstr #linkid strcasestr -fn strcasestr(cstr haystack, cstr needle):cstr +fx strcasestr(cstr haystack, cstr needle):cstr #linkid memrchr -fn memrchr(anyptr s, i32 c, u64 n):anyptr +fx memrchr(anyptr s, i32 c, u64 n):anyptr #linkid mempcpy -fn mempcpy(anyptr dst, anyptr src, u64 n):anyptr +fx mempcpy(anyptr dst, anyptr src, u64 n):anyptr // math.h @@ -668,438 +668,438 @@ const M_SQRT2 = 1.41421356237309504880 const M_SQRT1_2 = 0.70710678118654752440 #linkid acos -fn acos(f64 x):f64 +fx acos(f64 x):f64 #linkid acosf -fn acosf(f32 x):f32 +fx acosf(f32 x):f32 #linkid acosh -fn acosh(f64 x):f64 +fx acosh(f64 x):f64 #linkid acoshf -fn acoshf(f32 x):f32 +fx acoshf(f32 x):f32 #linkid asin -fn asin(f64 x):f64 +fx asin(f64 x):f64 #linkid asinf -fn asinf(f32 x):f32 +fx asinf(f32 x):f32 #linkid asinh -fn asinh(f64 x):f64 +fx asinh(f64 x):f64 #linkid asinhf -fn asinhf(f32 x):f32 +fx asinhf(f32 x):f32 #linkid atan -fn atan(f64 x):f64 +fx atan(f64 x):f64 #linkid atanf -fn atanf(f32 x):f32 +fx atanf(f32 x):f32 #linkid atan2 -fn atan2(f64 y, f64 x):f64 +fx atan2(f64 y, f64 x):f64 #linkid atan2f -fn atan2f(f32 y, f32 x):f32 +fx atan2f(f32 y, f32 x):f32 #linkid cos -fn cos(f64 x):f64 +fx cos(f64 x):f64 #linkid cosf -fn cosf(f32 x):f32 +fx cosf(f32 x):f32 #linkid sin -fn sin(f64 x):f64 +fx sin(f64 x):f64 #linkid sinf -fn sinf(f32 x):f32 +fx sinf(f32 x):f32 #linkid tan -fn tan(f64 x):f64 +fx tan(f64 x):f64 #linkid tanf -fn tanf(f32 x):f32 +fx tanf(f32 x):f32 #linkid atanh -fn atanh(f64 x):f64 +fx atanh(f64 x):f64 #linkid atanhf -fn atanhf(f32 x):f32 +fx atanhf(f32 x):f32 #linkid cosh -fn cosh(f64 x):f64 +fx cosh(f64 x):f64 #linkid coshf -fn coshf(f32 x):f32 +fx coshf(f32 x):f32 #linkid sinh -fn sinh(f64 x):f64 +fx sinh(f64 x):f64 #linkid sinhf -fn sinhf(f32 x):f32 +fx sinhf(f32 x):f32 #linkid sqrt -fn sqrt(f64 x):f64 +fx sqrt(f64 x):f64 #linkid sqrtf -fn sqrtf(f32 x):f32 +fx sqrtf(f32 x):f32 #linkid tanh -fn tanh(f64 x):f64 +fx tanh(f64 x):f64 #linkid tanhf -fn tanhf(f32 x):f32 +fx tanhf(f32 x):f32 #linkid exp -fn exp(f64 x):f64 +fx exp(f64 x):f64 #linkid expf -fn expf(f32 x):f32 +fx expf(f32 x):f32 #linkid exp2 -fn exp2(f64 x):f64 +fx exp2(f64 x):f64 #linkid exp2f -fn exp2f(f32 x):f32 +fx exp2f(f32 x):f32 #linkid expm1 -fn expm1(f64 x):f64 +fx expm1(f64 x):f64 #linkid expm1f -fn expm1f(f32 x):f32 +fx expm1f(f32 x):f32 #linkid fabs -fn fabs(f64 x):f64 +fx fabs(f64 x):f64 #linkid fabsf -fn fabsf(f32 x):f32 +fx fabsf(f32 x):f32 #linkid log -fn log(f64 x):f64 +fx log(f64 x):f64 #linkid logf -fn logf(f32 x):f32 +fx logf(f32 x):f32 #linkid log10 -fn log10(f64 x):f64 +fx log10(f64 x):f64 #linkid log10f -fn log10f(f32 x):f32 +fx log10f(f32 x):f32 #linkid log1p -fn log1p(f64 x):f64 +fx log1p(f64 x):f64 #linkid log1pf -fn log1pf(f32 x):f32 +fx log1pf(f32 x):f32 #linkid log2 -fn log2(f64 x):f64 +fx log2(f64 x):f64 #linkid log2f -fn log2f(f32 x):f32 +fx log2f(f32 x):f32 #linkid logb -fn logb(f64 x):f64 +fx logb(f64 x):f64 #linkid logbf -fn logbf(f32 x):f32 +fx logbf(f32 x):f32 // 幂函数 #linkid pow -fn pow(f64 x, f64 y):f64 +fx pow(f64 x, f64 y):f64 #linkid powf -fn powf(f32 x, f32 y):f32 +fx powf(f32 x, f32 y):f32 #linkid cbrt -fn cbrt(f64 x):f64 +fx cbrt(f64 x):f64 #linkid cbrtf -fn cbrtf(f32 x):f32 +fx cbrtf(f32 x):f32 #linkid hypot -fn hypot(f64 x, f64 y):f64 +fx hypot(f64 x, f64 y):f64 #linkid hypotf -fn hypotf(f32 x, f32 y):f32 +fx hypotf(f32 x, f32 y):f32 #linkid ceil -fn ceil(f64 x):f64 +fx ceil(f64 x):f64 #linkid ceilf -fn ceilf(f32 x):f32 +fx ceilf(f32 x):f32 #linkid floor -fn floor(f64 x):f64 +fx floor(f64 x):f64 #linkid floorf -fn floorf(f32 x):f32 +fx floorf(f32 x):f32 #linkid trunc -fn trunc(f64 x):f64 +fx trunc(f64 x):f64 #linkid truncf -fn truncf(f32 x):f32 +fx truncf(f32 x):f32 #linkid rint -fn rint(f64 x):f64 +fx rint(f64 x):f64 #linkid rintf -fn rintf(f32 x):f32 +fx rintf(f32 x):f32 #linkid nearbyint -fn nearbyint(f64 x):f64 +fx nearbyint(f64 x):f64 #linkid nearbyintf -fn nearbyintf(f32 x):f32 +fx nearbyintf(f32 x):f32 #linkid lrint -fn lrint(f64 x):i64 +fx lrint(f64 x):i64 #linkid lrintf -fn lrintf(f32 x):i64 +fx lrintf(f32 x):i64 #linkid llrint -fn llrint(f64 x):i64 +fx llrint(f64 x):i64 #linkid llrintf -fn llrintf(f32 x):i64 +fx llrintf(f32 x):i64 #linkid lround -fn lround(f64 x):i64 +fx lround(f64 x):i64 #linkid lroundf -fn lroundf(f32 x):i64 +fx lroundf(f32 x):i64 #linkid llround -fn llround(f64 x):i64 +fx llround(f64 x):i64 #linkid llroundf -fn llroundf(f32 x):i64 +fx llroundf(f32 x):i64 #linkid copysign -fn copysign(f64 x, f64 y):f64 +fx copysign(f64 x, f64 y):f64 #linkid copysignf -fn copysignf(f32 x, f32 y):f32 +fx copysignf(f32 x, f32 y):f32 #linkid frexp -fn frexp(f64 x, ptr exp):f64 +fx frexp(f64 x, ptr exp):f64 #linkid frexpf -fn frexpf(f32 x, ptr exp):f32 +fx frexpf(f32 x, ptr exp):f32 #linkid ldexp -fn ldexp(f64 x, i32 exp):f64 +fx ldexp(f64 x, i32 exp):f64 #linkid ldexpf -fn ldexpf(f32 x, i32 exp):f32 +fx ldexpf(f32 x, i32 exp):f32 #linkid modf -fn modf(f64 x, ptr iptr):f64 +fx modf(f64 x, ptr iptr):f64 #linkid modff -fn modff(f32 x, ptr iptr):f32 +fx modff(f32 x, ptr iptr):f32 #linkid scalbn -fn scalbn(f64 x, i32 n):f64 +fx scalbn(f64 x, i32 n):f64 #linkid scalbnf -fn scalbnf(f32 x, i32 n):f32 +fx scalbnf(f32 x, i32 n):f32 #linkid scalbln -fn scalbln(f64 x, i64 n):f64 +fx scalbln(f64 x, i64 n):f64 #linkid scalblnf -fn scalblnf(f32 x, i64 n):f32 +fx scalblnf(f32 x, i64 n):f32 #linkid round -fn round(f64 x):f64 +fx round(f64 x):f64 #linkid roundf -fn roundf(f32 x):f32 +fx roundf(f32 x):f32 #linkid ilogb -fn ilogb(f64 x):i32 +fx ilogb(f64 x):i32 #linkid ilogbf -fn ilogbf(f32 x):i32 +fx ilogbf(f32 x):i32 // 浮点余数和商函数 #linkid fmod -fn fmod(f64 x, f64 y):f64 +fx fmod(f64 x, f64 y):f64 #linkid fmodf -fn fmodf(f32 x, f32 y):f32 +fx fmodf(f32 x, f32 y):f32 #linkid remainder -fn remainder(f64 x, f64 y):f64 +fx remainder(f64 x, f64 y):f64 #linkid remainderf -fn remainderf(f32 x, f32 y):f32 +fx remainderf(f32 x, f32 y):f32 #linkid remquo -fn remquo(f64 x, f64 y, ptr quo):f64 +fx remquo(f64 x, f64 y, ptr quo):f64 #linkid remquof -fn remquof(f32 x, f32 y, ptr quo):f32 +fx remquof(f32 x, f32 y, ptr quo):f32 #linkid fmax -fn fmax(f64 x, f64 y):f64 +fx fmax(f64 x, f64 y):f64 #linkid fmaxf -fn fmaxf(f32 x, f32 y):f32 +fx fmaxf(f32 x, f32 y):f32 #linkid fmin -fn fmin(f64 x, f64 y):f64 +fx fmin(f64 x, f64 y):f64 #linkid fminf -fn fminf(f32 x, f32 y):f32 +fx fminf(f32 x, f32 y):f32 #linkid fdim -fn fdim(f64 x, f64 y):f64 +fx fdim(f64 x, f64 y):f64 #linkid fdimf -fn fdimf(f32 x, f32 y):f32 +fx fdimf(f32 x, f32 y):f32 // 融合乘加函数 #linkid fma -fn fma(f64 x, f64 y, f64 z):f64 +fx fma(f64 x, f64 y, f64 z):f64 #linkid fmaf -fn fmaf(f32 x, f32 y, f32 z):f32 +fx fmaf(f32 x, f32 y, f32 z):f32 // 特殊函数 #linkid erf -fn erf(f64 x):f64 +fx erf(f64 x):f64 #linkid erff -fn erff(f32 x):f32 +fx erff(f32 x):f32 #linkid erfc -fn erfc(f64 x):f64 +fx erfc(f64 x):f64 #linkid erfcf -fn erfcf(f32 x):f32 +fx erfcf(f32 x):f32 #linkid lgamma -fn lgamma(f64 x):f64 +fx lgamma(f64 x):f64 #linkid lgammaf -fn lgammaf(f32 x):f32 +fx lgammaf(f32 x):f32 #linkid tgamma -fn tgamma(f64 x):f64 +fx tgamma(f64 x):f64 #linkid tgammaf -fn tgammaf(f32 x):f32 +fx tgammaf(f32 x):f32 // NaN 函数 #linkid nan -fn nan(cstr tagp):f64 +fx nan(cstr tagp):f64 #linkid nanf -fn nanf(cstr tagp):f32 +fx nanf(cstr tagp):f32 // 下一个可表示值函数 #linkid nextafter -fn nextafter(f64 x, f64 y):f64 +fx nextafter(f64 x, f64 y):f64 #linkid nextafterf -fn nextafterf(f32 x, f32 y):f32 +fx nextafterf(f32 x, f32 y):f32 #linkid nexttoward -fn nexttoward(f64 x, f64 y):f64 +fx nexttoward(f64 x, f64 y):f64 #linkid nexttowardf -fn nexttowardf(f32 x, f64 y):f32 +fx nexttowardf(f32 x, f64 y):f32 // Bessel 函数 (POSIX 扩展) #linkid j0 -fn j0(f64 x):f64 +fx j0(f64 x):f64 #linkid j0f -fn j0f(f32 x):f32 +fx j0f(f32 x):f32 #linkid j1 -fn j1(f64 x):f64 +fx j1(f64 x):f64 #linkid j1f -fn j1f(f32 x):f32 +fx j1f(f32 x):f32 #linkid jn -fn jn(i32 n, f64 x):f64 +fx jn(i32 n, f64 x):f64 #linkid jnf -fn jnf(i32 n, f32 x):f32 +fx jnf(i32 n, f32 x):f32 #linkid y0 -fn y0(f64 x):f64 +fx y0(f64 x):f64 #linkid y0f -fn y0f(f32 x):f32 +fx y0f(f32 x):f32 #linkid y1 -fn y1(f64 x):f64 +fx y1(f64 x):f64 #linkid y1f -fn y1f(f32 x):f32 +fx y1f(f32 x):f32 #linkid yn -fn yn(i32 n, f64 x):f64 +fx yn(i32 n, f64 x):f64 #linkid ynf -fn ynf(i32 n, f32 x):f32 +fx ynf(i32 n, f32 x):f32 // GNU/BSD 扩展 #linkid drem -fn drem(f64 x, f64 y):f64 +fx drem(f64 x, f64 y):f64 #linkid dremf -fn dremf(f32 x, f32 y):f32 +fx dremf(f32 x, f32 y):f32 #linkid finite -fn finite(f64 x):i32 +fx finite(f64 x):i32 #linkid finitef -fn finitef(f32 x):i32 +fx finitef(f32 x):i32 #linkid scalb -fn scalb(f64 x, f64 n):f64 +fx scalb(f64 x, f64 n):f64 #linkid scalbf -fn scalbf(f32 x, f32 n):f32 +fx scalbf(f32 x, f32 n):f32 #linkid significand -fn significand(f64 x):f64 +fx significand(f64 x):f64 #linkid significandf -fn significandf(f32 x):f32 +fx significandf(f32 x):f32 #linkid lgamma_r -fn lgamma_r(f64 x, ptr signgamp):f64 +fx lgamma_r(f64 x, ptr signgamp):f64 #linkid lgammaf_r -fn lgammaf_r(f32 x, ptr signgamp):f32 +fx lgammaf_r(f32 x, ptr signgamp):f32 #linkid sincos -fn sincos(f64 x, ptr sin, ptr cos):void +fx sincos(f64 x, ptr sin, ptr cos):void #linkid sincosf -fn sincosf(f32 x, ptr sin, ptr cos):void +fx sincosf(f32 x, ptr sin, ptr cos):void #linkid exp10 -fn exp10(f64 x):f64 +fx exp10(f64 x):f64 #linkid exp10f -fn exp10f(f32 x):f32 +fx exp10f(f32 x):f32 #linkid pow10 -fn pow10(f64 x):f64 +fx pow10(f64 x):f64 #linkid pow10f -fn pow10f(f32 x):f32 +fx pow10f(f32 x):f32 // time.h @@ -1158,472 +1158,472 @@ type tm = struct { // Basic time functions #linkid time -fn time(ptr t):time_t +fx time(ptr t):time_t #linkid clock -fn clock():clock_t +fx clock():clock_t #linkid difftime -fn difftime(time_t time1, time_t time0):f64 +fx difftime(time_t time1, time_t time0):f64 #linkid mktime -fn mktime(ptr time_info):time_t +fx mktime(ptr time_info):time_t // Time formatting #linkid strftime -fn strftime(cstr s, u64 size, cstr format, ptr time_info):u64 +fx strftime(cstr s, u64 size, cstr format, ptr time_info):u64 #linkid strftime_l -fn strftime_l(cstr s, u64 size, cstr format, ptr time_info, locale_t locale):u64 +fx strftime_l(cstr s, u64 size, cstr format, ptr time_info, locale_t locale):u64 // Time conversion functions #linkid localtime -fn localtime(ptr timestamp):ptr +fx localtime(ptr timestamp):ptr #linkid gmtime -fn gmtime(ptr timestamp):ptr +fx gmtime(ptr timestamp):ptr #linkid asctime -fn asctime(ptr tm):cstr +fx asctime(ptr tm):cstr #linkid ctime -fn ctime(ptr timestamp):cstr +fx ctime(ptr timestamp):cstr // Thread-safe versions #linkid localtime_r -fn localtime_r(ptr timestamp, ptr result):ptr +fx localtime_r(ptr timestamp, ptr result):ptr #linkid gmtime_r -fn gmtime_r(ptr timestamp, ptr result):ptr +fx gmtime_r(ptr timestamp, ptr result):ptr #linkid asctime_r -fn asctime_r(ptr tm, cstr buf):cstr +fx asctime_r(ptr tm, cstr buf):cstr #linkid ctime_r -fn ctime_r(ptr timestamp, cstr buf):cstr +fx ctime_r(ptr timestamp, cstr buf):cstr // Time parsing #linkid strptime -fn strptime(cstr s, cstr format, ptr tm):cstr +fx strptime(cstr s, cstr format, ptr tm):cstr // High-resolution time functions #linkid timespec_get -fn timespec_get(ptr ts, i32 base):i32 +fx timespec_get(ptr ts, i32 base):i32 #linkid nanosleep -fn nanosleep(ptr req, ptr rem):i32 +fx nanosleep(ptr req, ptr rem):i32 // Clock functions #linkid clock_getres -fn clock_getres(clockid_t clk_id, ptr res):i32 +fx clock_getres(clockid_t clk_id, ptr res):i32 #linkid clock_gettime -fn clock_gettime(clockid_t clk_id, ptr tp):i32 +fx clock_gettime(clockid_t clk_id, ptr tp):i32 #linkid clock_settime -fn clock_settime(clockid_t clk_id, ptr tp):i32 +fx clock_settime(clockid_t clk_id, ptr tp):i32 #linkid clock_nanosleep -fn clock_nanosleep(clockid_t clk_id, i32 flags, ptr req, ptr rem):i32 +fx clock_nanosleep(clockid_t clk_id, i32 flags, ptr req, ptr rem):i32 #linkid clock_getcpuclockid -fn clock_getcpuclockid(i32 pid, ptr clk_id):i32 +fx clock_getcpuclockid(i32 pid, ptr clk_id):i32 // Timer functions #linkid timer_create -fn timer_create(clockid_t clk_id, anyptr sevp, ptr timerid):i32 +fx timer_create(clockid_t clk_id, anyptr sevp, ptr timerid):i32 #linkid timer_delete -fn timer_delete(timer_t timerid):i32 +fx timer_delete(timer_t timerid):i32 #linkid timer_settime -fn timer_settime(timer_t timerid, i32 flags, ptr new_value, ptr old_value):i32 +fx timer_settime(timer_t timerid, i32 flags, ptr new_value, ptr old_value):i32 #linkid timer_gettime -fn timer_gettime(timer_t timerid, ptr curr_value):i32 +fx timer_gettime(timer_t timerid, ptr curr_value):i32 #linkid timer_getoverrun -fn timer_getoverrun(timer_t timerid):i32 +fx timer_getoverrun(timer_t timerid):i32 // Timezone functions #linkid tzset -fn tzset():void +fx tzset():void // GNU/BSD extensions #linkid stime -fn stime(ptr t):i32 +fx stime(ptr t):i32 #linkid timegm -fn timegm(ptr tm):time_t +fx timegm(ptr tm):time_t #linkid getdate -fn getdate(cstr str):ptr +fx getdate(cstr str):ptr // unistd.h - File operations #linkid pipe -fn pipe(anyptr pipefd):i32 +fx pipe(anyptr pipefd):i32 #linkid pipe2 -fn pipe2(anyptr pipefd, i32 flags):i32 +fx pipe2(anyptr pipefd, i32 flags):i32 #linkid close -fn close(i32 fd):i32 +fx close(i32 fd):i32 #linkid posix_close -fn posix_close(i32 fd, i32 flags):i32 +fx posix_close(i32 fd, i32 flags):i32 #linkid dup -fn dup(i32 oldfd):i32 +fx dup(i32 oldfd):i32 #linkid dup2 -fn dup2(i32 oldfd, i32 newfd):i32 +fx dup2(i32 oldfd, i32 newfd):i32 #linkid dup3 -fn dup3(i32 oldfd, i32 newfd, i32 flags):i32 +fx dup3(i32 oldfd, i32 newfd, i32 flags):i32 #linkid lseek -fn lseek(i32 fd, i64 offset, i32 whence):i64 +fx lseek(i32 fd, i64 offset, i32 whence):i64 #linkid fsync -fn fsync(i32 fd):i32 +fx fsync(i32 fd):i32 #linkid fdatasync -fn fdatasync(i32 fd):i32 +fx fdatasync(i32 fd):i32 #linkid read -fn read(i32 fd, anyptr buf, u64 count):i64 +fx read(i32 fd, anyptr buf, u64 count):i64 #linkid write -fn write(i32 fd, anyptr buf, u64 count):i64 +fx write(i32 fd, anyptr buf, u64 count):i64 #linkid pread -fn pread(i32 fd, anyptr buf, u64 count, i64 offset):i64 +fx pread(i32 fd, anyptr buf, u64 count, i64 offset):i64 #linkid pwrite -fn pwrite(i32 fd, anyptr buf, u64 count, i64 offset):i64 +fx pwrite(i32 fd, anyptr buf, u64 count, i64 offset):i64 // unistd.h - File ownership and permissions #linkid chown -fn chown(cstr path, u32 owner, u32 group):i32 +fx chown(cstr path, u32 owner, u32 group):i32 #linkid fchown -fn fchown(i32 fd, u32 owner, u32 group):i32 +fx fchown(i32 fd, u32 owner, u32 group):i32 #linkid lchown -fn lchown(cstr path, u32 owner, u32 group):i32 +fx lchown(cstr path, u32 owner, u32 group):i32 #linkid fchownat -fn fchownat(i32 dirfd, cstr path, u32 owner, u32 group, i32 flags):i32 +fx fchownat(i32 dirfd, cstr path, u32 owner, u32 group, i32 flags):i32 // unistd.h - File linking #linkid link -fn link(cstr oldpath, cstr newpath):i32 +fx link(cstr oldpath, cstr newpath):i32 #linkid linkat -fn linkat(i32 olddirfd, cstr oldpath, i32 newdirfd, cstr newpath, i32 flags):i32 +fx linkat(i32 olddirfd, cstr oldpath, i32 newdirfd, cstr newpath, i32 flags):i32 #linkid symlink -fn symlink(cstr target, cstr linkpath):i32 +fx symlink(cstr target, cstr linkpath):i32 #linkid symlinkat -fn symlinkat(cstr target, i32 newdirfd, cstr linkpath):i32 +fx symlinkat(cstr target, i32 newdirfd, cstr linkpath):i32 #linkid readlink -fn readlink(cstr path, cstr buf, u64 bufsiz):i64 +fx readlink(cstr path, cstr buf, u64 bufsiz):i64 #linkid readlinkat -fn readlinkat(i32 dirfd, cstr path, cstr buf, u64 bufsiz):i64 +fx readlinkat(i32 dirfd, cstr path, cstr buf, u64 bufsiz):i64 #linkid unlink -fn unlink(cstr path):i32 +fx unlink(cstr path):i32 #linkid unlinkat -fn unlinkat(i32 dirfd, cstr path, i32 flags):i32 +fx unlinkat(i32 dirfd, cstr path, i32 flags):i32 #linkid rmdir -fn rmdir(cstr path):i32 +fx rmdir(cstr path):i32 #linkid truncate -fn truncate(cstr path, i64 length):i32 +fx truncate(cstr path, i64 length):i32 #linkid ftruncate -fn ftruncate(i32 fd, i64 length):i32 +fx ftruncate(i32 fd, i64 length):i32 // unistd.h - File access #linkid access -fn access(cstr path, i32 mode):i32 +fx access(cstr path, i32 mode):i32 #linkid faccessat -fn faccessat(i32 dirfd, cstr path, i32 mode, i32 flags):i32 +fx faccessat(i32 dirfd, cstr path, i32 mode, i32 flags):i32 // unistd.h - Directory operations #linkid chdir -fn chdir(cstr path):i32 +fx chdir(cstr path):i32 #linkid fchdir -fn fchdir(i32 fd):i32 +fx fchdir(i32 fd):i32 // unistd.h - Process control #linkid alarm -fn alarm(u32 seconds):u32 +fx alarm(u32 seconds):u32 #linkid sleep -fn sleep(int second) +fx sleep(int second) #linkid usleep -fn usleep(u32 usec):i32 +fx usleep(u32 usec):i32 #linkid pause -fn pause():i32 +fx pause():i32 #linkid _Fork -fn _fork():i32 +fx _fork():i32 #linkid execve -fn execve(cstr filename, ptr argv, ptr envp):i32 +fx execve(cstr filename, ptr argv, ptr envp):i32 #linkid execv -fn execv(cstr path, ptr argv):i32 +fx execv(cstr path, ptr argv):i32 // not support // #linkid execle -// fn execle(cstr path, cstr arg, ...):i32 +// fx execle(cstr path, cstr arg, ...):i32 // #linkid execl -// fn execl(cstr path, cstr arg, ...):i32 +// fx execl(cstr path, cstr arg, ...):i32 // #linkid execvp -// fn execvp(cstr file, ptr argv):i32 +// fx execvp(cstr file, ptr argv):i32 // #linkid execlp -// fn execlp(cstr file, cstr arg, ...):i32 +// fx execlp(cstr file, cstr arg, ...):i32 // #linkid fexecve -// fn fexecve(i32 fd, ptr argv, ptr envp):i32 +// fx fexecve(i32 fd, ptr argv, ptr envp):i32 // unistd.h - Process identification #linkid getpid -fn getpid():i32 +fx getpid():i32 #linkid getppid -fn getppid():i32 +fx getppid():i32 #linkid getpgrp -fn getpgrp():i32 +fx getpgrp():i32 #linkid getpgid -fn getpgid(i32 pid):i32 +fx getpgid(i32 pid):i32 #linkid setpgid -fn setpgid(i32 pid, i32 pgid):i32 +fx setpgid(i32 pid, i32 pgid):i32 #linkid setsid -fn setsid():i32 +fx setsid():i32 #linkid getsid -fn getsid(i32 pid):i32 +fx getsid(i32 pid):i32 #linkid ttyname -fn ttyname(i32 fd):cstr +fx ttyname(i32 fd):cstr #linkid ttyname_r -fn ttyname_r(i32 fd, cstr buf, u64 buflen):i32 +fx ttyname_r(i32 fd, cstr buf, u64 buflen):i32 #linkid isatty -fn isatty(i32 fd):i32 +fx isatty(i32 fd):i32 #linkid tcgetpgrp -fn tcgetpgrp(i32 fd):i32 +fx tcgetpgrp(i32 fd):i32 #linkid tcsetpgrp -fn tcsetpgrp(i32 fd, i32 pgrp):i32 +fx tcsetpgrp(i32 fd, i32 pgrp):i32 // unistd.h - User and group identification #linkid getuid -fn getuid():u32 +fx getuid():u32 #linkid geteuid -fn geteuid():u32 +fx geteuid():u32 #linkid getgid -fn getgid():u32 +fx getgid():u32 #linkid getegid -fn getegid():u32 +fx getegid():u32 #linkid getgroups -fn getgroups(i32 size, ptr list):i32 +fx getgroups(i32 size, ptr list):i32 #linkid setuid -fn setuid(u32 uid):i32 +fx setuid(u32 uid):i32 #linkid seteuid -fn seteuid(u32 euid):i32 +fx seteuid(u32 euid):i32 #linkid setgid -fn setgid(u32 gid):i32 +fx setgid(u32 gid):i32 #linkid setegid -fn setegid(u32 egid):i32 +fx setegid(u32 egid):i32 // unistd.h - Login and hostname #linkid getlogin -fn getlogin():cstr +fx getlogin():cstr #linkid getlogin_r -fn getlogin_r(cstr buf, u64 bufsize):i32 +fx getlogin_r(cstr buf, u64 bufsize):i32 #linkid gethostname -fn gethostname(cstr name, u64 len):i32 +fx gethostname(cstr name, u64 len):i32 #linkid ctermid -fn ctermid(cstr s):cstr +fx ctermid(cstr s):cstr // unistd.h - Command line options #linkid getopt -fn getopt(i32 argc, ptr argv, cstr optstring):i32 +fx getopt(i32 argc, ptr argv, cstr optstring):i32 // unistd.h - Configuration #linkid pathconf -fn pathconf(cstr path, i32 name):i64 +fx pathconf(cstr path, i32 name):i64 #linkid fpathconf -fn fpathconf(i32 fd, i32 name):i64 +fx fpathconf(i32 fd, i32 name):i64 #linkid sysconf -fn sysconf(i32 name):i64 +fx sysconf(i32 name):i64 #linkid confstr -fn confstr(i32 name, cstr buf, u64 len):u64 +fx confstr(i32 name, cstr buf, u64 len):u64 // unistd.h - POSIX extensions #linkid setreuid -fn setreuid(u32 ruid, u32 euid):i32 +fx setreuid(u32 ruid, u32 euid):i32 #linkid setregid -fn setregid(u32 rgid, u32 egid):i32 +fx setregid(u32 rgid, u32 egid):i32 #linkid lockf -fn lockf(i32 fd, i32 cmd, i64 len):i32 +fx lockf(i32 fd, i32 cmd, i64 len):i32 #linkid gethostid -fn gethostid():i64 +fx gethostid():i64 #linkid nice -fn nice(i32 inc):i32 +fx nice(i32 inc):i32 #linkid sync -fn sync():void +fx sync():void #linkid setpgrp -fn setpgrp():i32 +fx setpgrp():i32 #linkid crypt -fn crypt(cstr key, cstr salt):cstr +fx crypt(cstr key, cstr salt):cstr #linkid encrypt -fn encrypt(cstr block, i32 edflag):void +fx encrypt(cstr block, i32 edflag):void #linkid swab -fn swab(anyptr from, anyptr to, i64 n):void +fx swab(anyptr from, anyptr to, i64 n):void #linkid ualarm -fn ualarm(u32 value, u32 interval):u32 +fx ualarm(u32 value, u32 interval):u32 // unistd.h - BSD/GNU extensions #linkid brk -fn brk(anyptr addr):i32 +fx brk(anyptr addr):i32 #linkid sbrk -fn sbrk(i64 increment):anyptr +fx sbrk(i64 increment):anyptr #linkid vfork -fn vfork():i32 +fx vfork():i32 #linkid vhangup -fn vhangup():i32 +fx vhangup():i32 #linkid chroot -fn chroot(cstr path):i32 +fx chroot(cstr path):i32 #linkid getpagesize -fn getpagesize():i32 +fx getpagesize():i32 #linkid getdtablesize -fn getdtablesize():i32 +fx getdtablesize():i32 #linkid sethostname -fn sethostname(cstr name, u64 len):i32 +fx sethostname(cstr name, u64 len):i32 #linkid getdomainname -fn getdomainname(cstr name, u64 len):i32 +fx getdomainname(cstr name, u64 len):i32 #linkid setdomainname -fn setdomainname(cstr name, u64 len):i32 +fx setdomainname(cstr name, u64 len):i32 #linkid setgroups -fn setgroups(u64 size, ptr list):i32 +fx setgroups(u64 size, ptr list):i32 #linkid getpass -fn getpass(cstr prompt):cstr +fx getpass(cstr prompt):cstr #linkid daemon -fn daemon(i32 nochdir, i32 noclose):i32 +fx daemon(i32 nochdir, i32 noclose):i32 #linkid setusershell -fn setusershell():void +fx setusershell():void #linkid endusershell -fn endusershell():void +fx endusershell():void #linkid getusershell -fn getusershell():cstr +fx getusershell():cstr #linkid acct -fn acct(cstr filename):i32 +fx acct(cstr filename):i32 // #linkid syscall -// fn syscall(i64 number, ...):i64 +// fx syscall(i64 number, ...):i64 #linkid execvpe -fn execvpe(cstr file, ptr argv, ptr envp):i32 +fx execvpe(cstr file, ptr argv, ptr envp):i32 #linkid issetugid -fn issetugid():i32 +fx issetugid():i32 #linkid getentropy -fn getentropy(anyptr buffer, u64 length):i32 +fx getentropy(anyptr buffer, u64 length):i32 // unistd.h - GNU extensions #os linux #linkid setresuid -fn setresuid(u32 ruid, u32 euid, u32 suid):i32 +fx setresuid(u32 ruid, u32 euid, u32 suid):i32 #os linux #linkid setresgid -fn setresgid(u32 rgid, u32 egid, u32 sgid):i32 +fx setresgid(u32 rgid, u32 egid, u32 sgid):i32 #linkid getresuid -fn getresuid(ptr ruid, ptr euid, ptr suid):i32 +fx getresuid(ptr ruid, ptr euid, ptr suid):i32 #os linux #linkid getresgid -fn getresgid(ptr rgid, ptr egid, ptr sgid):i32 +fx getresgid(ptr rgid, ptr egid, ptr sgid):i32 #linkid get_current_dir_name -fn get_current_dir_name():cstr +fx get_current_dir_name():cstr #linkid syncfs -fn syncfs(i32 fd):i32 +fx syncfs(i32 fd):i32 #linkid euidaccess -fn euidaccess(cstr pathname, i32 mode):i32 +fx euidaccess(cstr pathname, i32 mode):i32 #linkid eaccess -fn eaccess(cstr pathname, i32 mode):i32 +fx eaccess(cstr pathname, i32 mode):i32 #linkid copy_file_range -fn copy_file_range(i32 fd_in, ptr off_in, i32 fd_out, ptr off_out, u64 len, u32 flags):i64 +fx copy_file_range(i32 fd_in, ptr off_in, i32 fd_out, ptr off_out, u64 len, u32 flags):i64 #linkid gettid -fn gettid():i32 +fx gettid():i32 // fcntl.h // Type definitions @@ -1808,75 +1808,75 @@ const SPLICE_F_GIFT = 8 // Basic file operations #linkid creat -fn creat(cstr pathname, mode_t mode):i32 +fx creat(cstr pathname, mode_t mode):i32 #linkid fcntl -fn fcntl(i32 fd, i32 cmd, anyptr flag):i32 +fx fcntl(i32 fd, i32 cmd, anyptr flag):i32 #linkid open -fn open(cstr pathname, i32 flags, u32 mode):i32 +fx open(cstr pathname, i32 flags, u32 mode):i32 #linkid openat -fn openat(i32 dirfd, cstr pathname, i32 flags, u32 mode):i32 +fx openat(i32 dirfd, cstr pathname, i32 flags, u32 mode):i32 // POSIX advisory functions #linkid posix_fadvise -fn posix_fadvise(i32 fd, off_t offset, off_t len, i32 advice):i32 +fx posix_fadvise(i32 fd, off_t offset, off_t len, i32 advice):i32 #linkid posix_fallocate -fn posix_fallocate(i32 fd, off_t offset, off_t len):i32 +fx posix_fallocate(i32 fd, off_t offset, off_t len):i32 // GNU/Linux extensions #linkid fallocate -fn fallocate(i32 fd, i32 mode, off_t offset, off_t len):i32 +fx fallocate(i32 fd, i32 mode, off_t offset, off_t len):i32 #linkid name_to_handle_at -fn name_to_handle_at(i32 dirfd, cstr pathname, anyptr handle, ptr mount_id, i32 flags):i32 +fx name_to_handle_at(i32 dirfd, cstr pathname, anyptr handle, ptr mount_id, i32 flags):i32 #linkid open_by_handle_at -fn open_by_handle_at(i32 mount_fd, anyptr handle, i32 flags):i32 +fx open_by_handle_at(i32 mount_fd, anyptr handle, i32 flags):i32 #linkid readahead -fn readahead(i32 fd, off_t offset, u64 count):i64 +fx readahead(i32 fd, off_t offset, u64 count):i64 #linkid sync_file_range -fn sync_file_range(i32 fd, off_t offset, off_t nbytes, u32 flags):i32 +fx sync_file_range(i32 fd, off_t offset, off_t nbytes, u32 flags):i32 // Splice operations #linkid vmsplice -fn vmsplice(i32 fd, anyptr iov, u64 nr_segs, u32 flags):i64 +fx vmsplice(i32 fd, anyptr iov, u64 nr_segs, u32 flags):i64 #linkid splice -fn splice(i32 fd_in, ptr off_in, i32 fd_out, ptr off_out, u64 len, u32 flags):i64 +fx splice(i32 fd_in, ptr off_in, i32 fd_out, ptr off_out, u64 len, u32 flags):i64 #linkid tee -fn tee(i32 fd_in, i32 fd_out, u64 len, u32 flags):i64 +fx tee(i32 fd_in, i32 fd_out, u64 len, u32 flags):i64 // signal.h #linkid std_args -fn std_args():[string] +fx std_args():[string] // 主机顺序转网络顺序 #linkid htons -fn htons(u16 host):u16 +fx htons(u16 host):u16 #linkid htonl -fn htonl(u32 host):u32 +fx htonl(u32 host):u32 // 网络顺序转主机顺序 #linkid ntohs -fn ntohs(u16 x):u16 +fx ntohs(u16 x):u16 #linkid ntohl -fn ntohl(u32 x):u32 +fx ntohl(u32 x):u32 #linkid inet_pton -fn inet_pton(i32 family, anyptr src_str, anyptr dst_buf):i32 +fx inet_pton(i32 family, anyptr src_str, anyptr dst_buf):i32 #linkid inet_ntop -fn inet_ntop(i32 family, anyptr src_buf, anyptr dst_str, i32 len):i32 +fx inet_ntop(i32 family, anyptr src_buf, anyptr dst_str, i32 len):i32 /* * Protections are chosen from these bits, or-ed together @@ -1900,7 +1900,7 @@ int MAP_RENAME = 0x20 // 通过空值 options 实现阻塞和非阻塞模式 #linkid waitpid -fn waitpid(int pid, ptr status, int options):int +fx waitpid(int pid, ptr status, int options):int // --- signal 相关 type sigset_t = struct { @@ -1933,47 +1933,47 @@ type signalfd_siginfo_t = struct { } #linkid sigemptyset -fn sigemptyset(ref sigset):i32 +fx sigemptyset(ref sigset):i32 #linkid sigaddset -fn sigaddset(ref sigset, i32 signo):i32 +fx sigaddset(ref sigset, i32 signo):i32 #linkid sigfillset -fn sigfillset(ref sigset):i32 +fx sigfillset(ref sigset):i32 #linkid sigprocmask -fn sigprocmask(i32 how, ref sigset, ptr oldset):i32 +fx sigprocmask(i32 how, ref sigset, ptr oldset):i32 #linkid signalfd -fn signalfd(int fd, ref mask, i32 flags):i32 +fx signalfd(int fd, ref mask, i32 flags):i32 #linkid prctl -fn prctl(int option, u64 arg2, u64 arg3, u64 arg4, u64 arg5):int +fx prctl(int option, u64 arg2, u64 arg3, u64 arg4, u64 arg5):int #linkid uv_hrtime -fn uv_hrtime():u64 +fx uv_hrtime():u64 // 读取当前全局的 errno 编码 #linkid rt_errno -fn errno():int +fx errno():int #linkid rt_get_envs -fn get_envs():[string] +fx get_envs():[string] #linkid fork -fn fork():int +fx fork():int #linkid getcwd -fn getcwd(cstr path, uint size):cstr +fx getcwd(cstr path, uint size):cstr #linkid mmap -fn mmap(anyptr addr, int len, int prot, int flags, int fd, int off):anyptr +fx mmap(anyptr addr, int len, int prot, int flags, int fd, int off):anyptr #linkid munmap -fn munmap(anyptr addr, int len) +fx munmap(anyptr addr, int len) #linkid isprint -fn isprint(u8 c):bool +fx isprint(u8 c):bool #linkid isspace -fn isspace(u8 c):bool +fx isspace(u8 c):bool diff --git a/std/reflect/main.n b/std/reflect/main.n index e302ea7b..9a007909 100644 --- a/std/reflect/main.n +++ b/std/reflect/main.n @@ -178,10 +178,6 @@ fn type_t.to_string(&self):string { } } - - - - // ----------------------------------------------- value of ------------------------------------------------------------ type vec_t = struct{ anyptr data @@ -189,6 +185,7 @@ type vec_t = struct{ i64 capacity i64 element_size i64 hash + anyptr allocator } type string_t = vec_t diff --git a/std/runtime/main.n b/std/runtime/main.n index a7f9f7bf..4b71378c 100644 --- a/std/runtime/main.n +++ b/std/runtime/main.n @@ -1,86 +1,86 @@ #linkid rt_vec_new -fn vec_new(int hash, int element_hash, int len, anyptr value_ref):vec! +fx vec_new(int hash, int element_hash, int len, anyptr value_ref):vec! #linkid rt_vec_cap -fn vec_cap(int hash, int element_hash, int cap):vec! +fx vec_cap(int hash, int element_hash, int cap):vec! #linkid rt_vec_alloc -fn vec_alloc(int hash, int element_hash, int cap):anyptr! +fx vec_alloc(int hash, int element_hash, int cap):anyptr! #linkid rt_vec_new_out -fn vec_new_out(anyptr out, int hash, int element_hash, int cap) +fx vec_new_out(anyptr out, int hash, int element_hash, int cap) #linkid rt_vec_push -fn vec_push(anyptr list, int element_hash, anyptr val) +fx vec_push(anyptr list, int element_hash, anyptr val) #linkid rt_vec_grow -fn vec_grow(anyptr list, int element_hash, int custom_capacity) +fx vec_grow(anyptr list, int element_hash, int custom_capacity) #linkid rt_vec_slice -fn vec_slice(anyptr list, int start, int end):vec! +fx vec_slice(anyptr list, int start, int end):vec! #linkid rt_vec_append -fn vec_append(anyptr list1, anyptr list2, int element_hash) +fx vec_append(anyptr list1, anyptr list2, int element_hash) #linkid rt_vec_concat -fn vec_concat(anyptr list1, anyptr list2, int element_hash):vec +fx vec_concat(anyptr list1, anyptr list2, int element_hash):vec #linkid rt_set_new -fn set_new(int hash, int key_hash):set +fx set_new(int hash, int key_hash):set #linkid rt_set_add -fn set_add(anyptr s, anyptr key):bool +fx set_add(anyptr s, anyptr key):bool #linkid rt_set_contains -fn set_contains(anyptr s, anyptr key):bool +fx set_contains(anyptr s, anyptr key):bool #linkid rt_set_delete -fn set_delete(anyptr s, anyptr key) +fx set_delete(anyptr s, anyptr key) #linkid rt_set_new_out -fn set_new_out(anyptr out, int hash, int key_hash) +fx set_new_out(anyptr out, int hash, int key_hash) #linkid rt_map_new -fn map_new(int hash, int key_hash, int value_hash):map +fx map_new(int hash, int key_hash, int value_hash):map #linkid rt_map_alloc -fn map_alloc(int hash, int key_hash, int value_hash):anyptr +fx map_alloc(int hash, int key_hash, int value_hash):anyptr #linkid rt_map_new_out -fn map_new_out(anyptr out, int hash, int key_hash, int value_hash) +fx map_new_out(anyptr out, int hash, int key_hash, int value_hash) #linkid rt_map_delete -fn map_delete(anyptr m, anyptr key) +fx map_delete(anyptr m, anyptr key) #linkid rt_map_contains -fn map_contains(anyptr m, anyptr key):bool +fx map_contains(anyptr m, anyptr key):bool #linkid rt_map_assign -fn map_assign(anyptr m, anyptr key_ref):anyptr +fx map_assign(anyptr m, anyptr key_ref):anyptr #linkid rt_string_ref -fn string_ref(anyptr s):anyptr +fx string_ref(anyptr s):anyptr #linkid rt_processor_index -fn processor_index():int +fx processor_index():int #linkid runtime_force_gc -fn gc() +fx gc() #linkid runtime_malloc_bytes -fn malloc_bytes():i64 +fx malloc_bytes():i64 #linkid gc_malloc -fn gc_malloc(int hash):anyptr +fx gc_malloc(int hash):anyptr #linkid gc_malloc_size -fn gc_malloc_size(int size):anyptr +fx gc_malloc_size(int size):anyptr #linkid rt_string_new -fn string_new(anyptr s):string +fx string_new(anyptr s):string #linkid rt_string_ref_new -fn string_ref_new(anyptr s, int len):string +fx string_ref_new(anyptr s, int len):string #linkid rt_in_heap -fn in_heap(anyptr addr):bool +fx in_heap(anyptr addr):bool diff --git a/tests/features/20221025_09_map.c b/tests/features/20221025_09_map.c index fc7c2c60..7c7f3af7 100644 --- a/tests/features/20221025_09_map.c +++ b/tests/features/20221025_09_map.c @@ -8,7 +8,7 @@ static void test_basic() { "3\n" "2\n" "110\n" - "coroutine 'main' panic: 'key 'b' not found in map' at cases/20221025_09_map.n:24:15\n"; + "panic: 'key 'b' not found in map' at cases/20221025_09_map.n:24:15\n"; assert_string_equal(raw, str); } diff --git a/tests/features/20240329_00_struct_ptr.c b/tests/features/20240329_00_struct_ptr.c index e0e73a2a..bc5265c6 100644 --- a/tests/features/20240329_00_struct_ptr.c +++ b/tests/features/20240329_00_struct_ptr.c @@ -14,7 +14,7 @@ static void test_basic() { "in test_self hualaka 30 true\n" "hualaka 32 true\n"; // "invalid memory address or nil pointer dereference\n" - // "coroutine 'main' panic: 'invalid memory address or nil pointer dereference' at 20240329_00_struct_ptr/main.n:33:5\n"; + // "panic: 'invalid memory address or nil pointer dereference' at 20240329_00_struct_ptr/main.n:33:5\n"; assert_string_equal(raw, str); } diff --git a/tests/features/20241214_00_panic.c b/tests/features/20241214_00_panic.c index e3d55526..3e2622b8 100644 --- a/tests/features/20241214_00_panic.c +++ b/tests/features/20241214_00_panic.c @@ -4,7 +4,7 @@ static void test_basic() { char *raw = exec_output(); char *str = "hello world\n" "catch panic: index out of range [20] with length 0\n" - "coroutine 'main' panic: 'in here' at cases/20241214_00_panic.n:18:17\n"; + "panic: 'in here' at cases/20241214_00_panic.n:18:17\n"; assert_string_equal(raw, str); } diff --git a/tests/features/20250329_00_temp_test.c b/tests/features/20250329_00_temp_test.c index ea1d8d00..87b48417 100644 --- a/tests/features/20250329_00_temp_test.c +++ b/tests/features/20250329_00_temp_test.c @@ -9,6 +9,7 @@ int main(void) { // chdir("/Users/weiwenhao/Code/emoji-api"); // setenv("ENTRY_FILE", "main.n", 1); + VERBOSE = true; feature_test_build(); sleep(1); diff --git a/tests/features/20260224_01_fx_basic.c b/tests/features/20260224_01_fx_basic.c new file mode 100644 index 00000000..67fba809 --- /dev/null +++ b/tests/features/20260224_01_fx_basic.c @@ -0,0 +1,5 @@ +#include "tests/test.h" + +int main(void) { + feature_testar_test(NULL); +} diff --git a/tests/features/20260301_00_defer.c b/tests/features/20260301_00_defer.c new file mode 100644 index 00000000..67fba809 --- /dev/null +++ b/tests/features/20260301_00_defer.c @@ -0,0 +1,5 @@ +#include "tests/test.h" + +int main(void) { + feature_testar_test(NULL); +} diff --git a/tests/features/cases/20221025_07_list.testar b/tests/features/cases/20221025_07_list.testar index 7a2b1554..212ca610 100644 --- a/tests/features/cases/20221025_07_list.testar +++ b/tests/features/cases/20221025_07_list.testar @@ -82,7 +82,7 @@ fn main():void! { } --- output.txt -coroutine 'main' panic: 'index out of range [0] with length 0' at nature-test/main.n:5:24 +panic: 'index out of range [0] with length 0' at nature-test/main.n:5:24 === test_copy --- main.n @@ -105,7 +105,7 @@ fn main():void! { } --- output.txt -coroutine 'main' panic: 'index out of range [-1] with length 4' at nature-test/main.n:3:18 +panic: 'index out of range [-1] with length 4' at nature-test/main.n:3:18 @@ -118,7 +118,7 @@ fn main():void! { } --- output.txt -coroutine 'main' panic: 'index out of range [100123111] with length 4' at nature-test/main.n:3:26 +panic: 'index out of range [100123111] with length 4' at nature-test/main.n:3:26 === test_in_range1 @@ -179,4 +179,4 @@ fn main():void! { } --- output.txt -coroutine 'main' panic: 'index out of range [-2] with length 8' at nature-test/main.n:5:10 +panic: 'index out of range [-2] with length 8' at nature-test/main.n:5:10 diff --git a/tests/features/cases/20250221_00_try_catch.testar b/tests/features/cases/20250221_00_try_catch.testar index 665d6413..8cb4d437 100644 --- a/tests/features/cases/20250221_00_try_catch.testar +++ b/tests/features/cases/20250221_00_try_catch.testar @@ -53,7 +53,7 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'index out of range [12] with length 0' at nature-test/main.n:4:19 +panic: 'index out of range [12] with length 0' at nature-test/main.n:4:19 === test_nested --- main.n diff --git a/tests/features/cases/20250311_00_interface.testar b/tests/features/cases/20250311_00_interface.testar index 736bad91..a7264323 100644 --- a/tests/features/cases/20250311_00_interface.testar +++ b/tests/features/cases/20250311_00_interface.testar @@ -51,7 +51,7 @@ fn main():void! { } --- output.txt -nature-test/main.n:12:2: the fn 'perimeter' of type 'main.rectangle' mismatch interface 'main.measurable' +nature-test/main.n:15:2: the fn 'perimeter' of type 'main.rectangle' mismatch interface 'main.measurable' === test_mismatch_interface2 --- main.n @@ -81,7 +81,7 @@ fn main():void! { } --- output.txt -nature-test/main.n:23:17: the fn 'area' of type 'main.rectangle' mismatch interface 'main.measurable' +nature-test/main.n:23:17: type 'main.rectangle(struct)' not impl 'main.measurable(interface)' interface === test_basic --- main.n @@ -279,9 +279,7 @@ fn main():void! { } --- output.txt -nature-test/main.n:33:22: the fn 'perimeter' of type 'main.rectangle' mismatch interface 'main.measurable' - - +nature-test/main.n:33:22: type 'main.rectangle(struct)' not impl 'main.measurable(interface)' interface === test_typedef_arg_mismatch @@ -539,8 +537,7 @@ fn main():void! { } --- output.txt -nature-test/main.n:14:2: type 'main.rectangle' not impl fn 'update' for interface 'main.updatable' - +nature-test/main.n:10:41: type 'main.rectangle' not impl fn 'update' for interface 'main.updatable' === test_combination_impl_failed2 @@ -678,7 +675,7 @@ fn main():void! { } --- output.txt -nature-test/main.n:15:2: duplicate method 'area' +nature-test/main.n:11:43: duplicate method 'area' === test_duck_type_deny --- main.n @@ -723,7 +720,7 @@ fn main():void! { } --- output.txt -nature-test/main.n:38:13: type 'main.rectangle' not impl 'main.combination' interface +nature-test/main.n:38:13: type 'main.rectangle(struct)' not impl 'main.combination(interface)' interface === test_combination --- main.n diff --git a/tests/features/cases/20250315_00_error_interface.testar b/tests/features/cases/20250315_00_error_interface.testar index 258a7175..d8b059cc 100644 --- a/tests/features/cases/20250315_00_error_interface.testar +++ b/tests/features/cases/20250315_00_error_interface.testar @@ -57,7 +57,7 @@ fn main():void! { } --- output.txt -coroutine 'main' panic: 'index out of range [11] with length 10' at nature-test/main.n:3:21 +panic: 'index out of range [11] with length 10' at nature-test/main.n:3:21 === test_catch_panic --- main.n diff --git a/tests/features/cases/20250329_00_temp_test.n b/tests/features/cases/20250329_00_temp_test.n index 3e26d584..4a44042d 100644 --- a/tests/features/cases/20250329_00_temp_test.n +++ b/tests/features/cases/20250329_00_temp_test.n @@ -1,8 +1,3 @@ -fn vec.temp(*self):int { - return self.len() // self 的类型推断出现了严重的问题?这可能源于? -} - fn main() { - [int] a = [1, 2, 3] - a.temp() + println('hello world') } \ No newline at end of file diff --git a/tests/features/cases/20250401_00_reg_alloc.testar b/tests/features/cases/20250401_00_reg_alloc.testar index 73eaf4c1..0ffb9793 100644 --- a/tests/features/cases/20250401_00_reg_alloc.testar +++ b/tests/features/cases/20250401_00_reg_alloc.testar @@ -68,7 +68,7 @@ fn main():void! { } --- output.txt -coroutine 'main' panic: 'index out of range [2] with length 2' at nature-test/main.n:13:22 +panic: 'index out of range [2] with length 2' at nature-test/main.n:13:22 === test_live_in_phi_not_rename --- main.n diff --git a/tests/features/cases/20250402_00_test_error.testar b/tests/features/cases/20250402_00_test_error.testar index 8aeae7a5..58d8bf38 100644 --- a/tests/features/cases/20250402_00_test_error.testar +++ b/tests/features/cases/20250402_00_test_error.testar @@ -128,7 +128,7 @@ fn main():void! { } --- output.txt -coroutine 'main' panic: 'index out of range [8] with length 4' at nature-test/main.n:3:18 +panic: 'index out of range [8] with length 4' at nature-test/main.n:3:18 === test_vec_assign_error --- main.n @@ -138,7 +138,7 @@ fn main():void! { } --- output.txt -coroutine 'main' panic: 'index out of range [8] with length 4' at nature-test/main.n:3:16 +panic: 'index out of range [8] with length 4' at nature-test/main.n:3:16 === test_catch_vec_assign --- main.n diff --git a/tests/features/cases/20250419_00_test_error.testar b/tests/features/cases/20250419_00_test_error.testar index fe3c31f0..eb28d3f6 100644 --- a/tests/features/cases/20250419_00_test_error.testar +++ b/tests/features/cases/20250419_00_test_error.testar @@ -146,4 +146,4 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'slice [0:6] out of vec with length 3' at nature-test/main.n:3:12 +panic: 'slice [0:6] out of vec with length 3' at nature-test/main.n:3:12 diff --git a/tests/features/cases/20250617_00_reflect.testar b/tests/features/cases/20250617_00_reflect.testar index 767ec901..58557ee6 100644 --- a/tests/features/cases/20250617_00_reflect.testar +++ b/tests/features/cases/20250617_00_reflect.testar @@ -27,7 +27,7 @@ fn main() { } --- output.txt -56 +64 3387576668 19 0 @@ -38,7 +38,7 @@ a 3332055654 0 b 3365180733 8 1 3365180733 2 0 c 398550328 16 -40 398550328 13 0 +48 398550328 13 0 === test_nesting --- main.n @@ -68,7 +68,7 @@ fn main() { var clothing_fields = t.fields[2] var clothing_type = reflect.typeof_hash(clothing_fields.hash) - assert(clothing_type.size == 80) + assert(clothing_type.size == 96) assert(clothing_type.kind == reflect.STRUCT) for field in clothing_type.fields { @@ -79,15 +79,15 @@ fn main() { } --- output.txt -136 +160 3387576668 19 0 4 398550328 -40 398550328 13 0 +48 398550328 13 0 398550328 -40 398550328 13 0 +48 398550328 13 0 === test_basic_type @@ -140,7 +140,7 @@ fn main() { 1 2 0 -40 +48 13 0 @@ -163,7 +163,7 @@ fn main() { } --- output.txt -40 +48 14 1 4 @@ -226,10 +226,10 @@ fn main() { 56 16 2 -40 +48 13 0 -40 +48 14 1 @@ -259,7 +259,7 @@ fn main() { 40 17 1 -40 +48 13 0 @@ -282,7 +282,7 @@ fn main() { } --- output.txt -152 +168 18 9 8 3332055654 9 0 @@ -291,8 +291,8 @@ fn main() { 1 3365180733 2 0 1 3365180733 2 0 1 3365180733 2 0 -40 398550328 13 0 -40 3931237662 14 1 +48 398550328 13 0 +48 3931237662 14 1 40 718442705 17 1 === test_reflect_ptr diff --git a/tests/features/cases/20250623_00_for_in.testar b/tests/features/cases/20250623_00_for_in.testar index b5bffe3e..c9f21771 100644 --- a/tests/features/cases/20250623_00_for_in.testar +++ b/tests/features/cases/20250623_00_for_in.testar @@ -26,3 +26,20 @@ fn main() { 0 4 1007465396 0 1 29 923577301 8 2 0 0 0 + +=== test_for_in_range +--- main.n +fn main() { + u32 len = 5 + + for i in 0..len { + println(i) + } +} + +--- output.txt +0 +1 +2 +3 +4 diff --git a/tests/features/cases/20250623_02_json.testar b/tests/features/cases/20250623_02_json.testar index ef093397..fd72ddb0 100644 --- a/tests/features/cases/20250623_02_json.testar +++ b/tests/features/cases/20250623_02_json.testar @@ -34,7 +34,7 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'expected boolean value at position 0' at nature-test/main.n:6:15 +panic: 'expected boolean value at position 0' at nature-test/main.n:6:15 === test_deserialize_u8_string --- main.n @@ -128,7 +128,7 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'expected `"` at position 27' at nature-test/main.n:14:15 +panic: 'expected `"` at position 27' at nature-test/main.n:14:15 === test_deserialize_struct --- main.n @@ -166,7 +166,7 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'type assert failed' at nature-test/main.n:9:27 +panic: 'type assert failed' at nature-test/main.n:9:27 === test_deserialize_any_failed2 --- main.n @@ -182,7 +182,7 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'type assert failed' at nature-test/main.n:9:18 +panic: 'type assert failed' at nature-test/main.n:9:18 === test_deserialize_any --- main.n diff --git a/tests/features/cases/20250630_00_json_escape.testar b/tests/features/cases/20250630_00_json_escape.testar index 2b157d2b..ae672e86 100644 --- a/tests/features/cases/20250630_00_json_escape.testar +++ b/tests/features/cases/20250630_00_json_escape.testar @@ -34,7 +34,7 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'invalid character in string literal at position 6' at nature-test/main.n:6:15 +panic: 'invalid character in string literal at position 6' at nature-test/main.n:6:15 === test_json_escape_failed2 @@ -51,7 +51,7 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'invalid escape sequence at position 7' at nature-test/main.n:6:15 +panic: 'invalid escape sequence at position 7' at nature-test/main.n:6:15 === test_json_escape --- main.n diff --git a/tests/features/cases/20250716_00_tcp.testar b/tests/features/cases/20250716_00_tcp.testar index 6ba8a298..55353417 100644 --- a/tests/features/cases/20250716_00_tcp.testar +++ b/tests/features/cases/20250716_00_tcp.testar @@ -187,7 +187,7 @@ fn main() { --- output.txt server is start -coroutine '1' panic: 'conn closed' at nature-test/main.n:17:15 +panic: 'conn closed' at nature-test/main.n:17:15 === test_url_parser --- main.n diff --git a/tests/features/cases/20250723_00_udp.testar b/tests/features/cases/20250723_00_udp.testar index 29cda41a..ecaaa904 100644 --- a/tests/features/cases/20250723_00_udp.testar +++ b/tests/features/cases/20250723_00_udp.testar @@ -215,7 +215,7 @@ fn main() { --- output.txt send success, recv msg hello world!! -coroutine 'main' panic: 'socket closed' at nature-test/main.n:29:15 +panic: 'socket closed' at nature-test/main.n:29:15 === test_dns --- main.n @@ -250,7 +250,7 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'unknown node or service' at nature-test/main.n:7:15 +panic: 'unknown node or service' at nature-test/main.n:7:15 === test_sendto_speed --- main.n diff --git a/tests/features/cases/20250819_00_vec_slice.testar b/tests/features/cases/20250819_00_vec_slice.testar index 05c90a9a..9946546e 100644 --- a/tests/features/cases/20250819_00_vec_slice.testar +++ b/tests/features/cases/20250819_00_vec_slice.testar @@ -18,7 +18,7 @@ fn main() { } --- output.txt -coroutine 'main' panic: 'slice [0:6] out of vec with length 5' at nature-test/main.n:3:24 +panic: 'slice [0:6] out of vec with length 5' at nature-test/main.n:3:24 === test_slice_2 diff --git a/tests/features/cases/20250923_00_test_error.testar b/tests/features/cases/20250923_00_test_error.testar index 8f7ac065..f49284e8 100644 --- a/tests/features/cases/20250923_00_test_error.testar +++ b/tests/features/cases/20250923_00_test_error.testar @@ -182,3 +182,49 @@ fn main() { --- output.txt nature-test/main.n:7:18: type inconsistency, expect=main.result(struct), actual=main.result(struct) + +=== test_fn_fx_type_mismatch +--- main.n +fn normal() {} + +fn main() { + fx() cb = normal +} + +--- output.txt +nature-test/main.n:4:20: type inconsistency, expect=fx(...):void, actual=fn(...):void + +=== test_fx_cannot_call_fn +--- main.n +fn normal() {} + +fx worker() { + normal() +} + +fn main() {} + +--- output.txt +nature-test/main.n:4:10: calling fn `normal` from fx `worker` is not allowed. + +=== test_custom_direct_type_interface +--- main.n +import libc + +type allocatable = interface{ + fn new() +} + +type heap_t:allocatable = int + +fx heap_t.new(int v) { + println(v) +} + +fn main() { + heap_t h = 0 + h.new(1) +} + +--- output.txt +nature-test/main.n:7:23: type 'main.heap_t' not impl fn 'new' for interface 'main.allocatable' diff --git a/tests/features/cases/20260125_00_toylang/lexer/lexer.n b/tests/features/cases/20260125_00_toylang/lexer/lexer.n index 9df1bf99..3b4319f2 100644 --- a/tests/features/cases/20260125_00_toylang/lexer/lexer.n +++ b/tests/features/cases/20260125_00_toylang/lexer/lexer.n @@ -1,15 +1,15 @@ import toylang.token.token type Lexer = struct { + int line // current line number + int column // current column number string input // source code input int position // current position in input (points to current char) int readPosition // current reading position in input (after current char) string ch // current char under examination - int line // current line number - int column // current column number } -fn newLexer( string input): Lexer { +fn newLexer(string input): Lexer { var l = Lexer { input: input, position: 0, diff --git a/tests/features/cases/20260223_00_generics_method.testar b/tests/features/cases/20260223_00_generics_method.testar index 1a97d16f..8a2a8cb8 100644 --- a/tests/features/cases/20260223_00_generics_method.testar +++ b/tests/features/cases/20260223_00_generics_method.testar @@ -108,4 +108,3 @@ fn main() { true 12 false - diff --git a/tests/features/cases/20260224_01_fx_basic.testar b/tests/features/cases/20260224_01_fx_basic.testar new file mode 100644 index 00000000..1d72283f --- /dev/null +++ b/tests/features/cases/20260224_01_fx_basic.testar @@ -0,0 +1,117 @@ +=== test_fx_basic +--- main.n +fx main() { + var sum = 1 + 1 + println(sum) + assert(sum == 2) +} + +=== test_const_string +--- main.n +fx main() { + var str = 'hello world' + println(str) +} + +--- output.txt +hello world + +=== test_allocator +--- main.n +import allocator as ac + +type foo_t = struct{ + string a + float c +} + +fx main() { + ptr f = ac.new(foo_t{a: 'hello', c: 1.1}) + println(f.a, f.c) + + ptr b = ac.new(true) + println(*b) + ac.free(b) +} + + +--- output.txt +hello 1.100000 +true + + +=== test_arena_alloc +--- main.n +import allocator.arena + +type foo_t = struct{ + string a // 48 + float c // 8 +} + +fx main() { + var ar = arena.init(4096) + println(ar.current.used) + + ptr f = ar.new(foo_t{a: 'hello', c: 1.1}) + println(f.a, f.c) + + ptr b = ar.new(true) + println(*b) + + println(ar.current.used) + ar.deinit() +} + +--- output.txt +0 +hello 1.100000 +true +57 + +=== test_defer_alloc +--- main.n +import allocator.arena + +type foo_t = struct{ + string a + float c +} + +fx main() { + var ar = arena.init(4096) + defer ar.deinit() + + ptr b = ar.new(true) + var f = ar.new(foo_t{a: 'hello', c: 1.1}) + println(f.a, f.c) + + + println(ar.current.used) +} + +--- output.txt +hello 1.100000 +64 + + +=== test_vec_basic +--- main.n +import allocator as ac + +fn main() { + var list = vec.alloc(ac.heap, 200 as u8, 10) + defer list.deinit() + + println(list[0], list[9]) + list[0] = 12 + list[9] = 15 + println(list[0], list[9]) + list.push(100) + println(list[10]) +} + +--- output.txt +200 200 +12 15 +100 diff --git a/tests/features/cases/20260301_00_defer.testar b/tests/features/cases/20260301_00_defer.testar new file mode 100644 index 00000000..74a8559d --- /dev/null +++ b/tests/features/cases/20260301_00_defer.testar @@ -0,0 +1,192 @@ +=== test_lifo_same_scope +--- main.n +fn main() { + defer { + println('a') + } + defer { + println('b') + } +} + +--- output.txt +b +a + +=== test_stmt_body +--- main.n +fn main() { + defer println('hello world') + println('hello after') +} + +--- output.txt +hello after +hello world + +=== test_nested_scope_order +--- main.n +fn dump(int n) { + println(n) +} + +fn main() { + dump(0) + defer { + dump(2) + } + + if true { + defer { + dump(3) + } + dump(4) + } + + dump(1) +} + +--- output.txt +0 +4 +3 +1 +2 + +=== test_return_unwind +--- main.n +fn dump(int n) { + println(n) +} + +fn calc():int { + dump(0) + defer { + dump(2) + } + + if true { + defer { + dump(3) + } + return 7 + } + + dump(1) + + return 0 +} + +fn main() { + dump(calc()) +} + +--- output.txt +0 +3 +2 +7 + +=== test_continue_unwind +--- main.n +fn main() { + for i32 i = 0; i < 2; i += 1 { + if i == 0 { + defer { + println('c0') + } + continue + } + + defer { + println('c1') + } + continue + } +} + +--- output.txt +c0 +c1 + +=== test_break_unwind +--- main.n +fn main() { + for i32 i = 0; i < 3; i += 1 { + defer { + println('before_break') + } + break + defer { + println('after_break') + } + } + println('done') +} + +--- output.txt +before_break +done + +=== test_throw_unwind +--- main.n +fn boom():void! { + defer { + println('cleanup') + } + throw errorf('x') +} + +fn main() { + try { + boom() + } catch e { + println('caught', e.msg()) + } +} + +--- output.txt +cleanup +caught x + +=== test_runtime_error_unwind +--- main.n +fn main() { + try { + defer { + println('cleanup') + } + [int] list = [] + var b = list[1] + } catch e { + println('caught') + } +} + +--- output.txt +cleanup +caught + +=== test_defer_eval_time_like_zig +--- main.n +fn main() { + int a = 1 + defer { + println(a) + } + a = 2 +} + +--- output.txt +2 + +=== test_invalid_control_in_defer +--- main.n +fn main() { + defer { + return + } +} + +--- output.txt +nature-test/main.n:3:14: return/break/continue/throw/ret are not allowed inside defer block diff --git a/tests/fx/20221025_02_sum.c b/tests/fx/20221025_02_sum.c deleted file mode 100644 index faddfb39..00000000 --- a/tests/fx/20221025_02_sum.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "tests/test.h" -#include - -static void test_basic() { -// char *raw = exec_output(); -// char *str = "foo=-28\nbar=-16"; - -// assert_string_equal(raw, str); -} - -int main(void) { - TEST_BASIC -} \ No newline at end of file diff --git a/tests/fx/cases/20260205_00_sum.n b/tests/fx/cases/20260205_00_sum.n deleted file mode 100644 index 704f77f0..00000000 --- a/tests/fx/cases/20260205_00_sum.n +++ /dev/null @@ -1,3 +0,0 @@ -fx main() { - var n = 1 + 1 -} \ No newline at end of file diff --git a/tests/test_runtime.h b/tests/test_runtime.h index e049eb83..7a8d6094 100644 --- a/tests/test_runtime.h +++ b/tests/test_runtime.h @@ -20,4 +20,6 @@ caller_t rt_caller_data; // 仅需要修复一下 gc_bits 数据即可 uint64_t rt_rtype_count; rtype_t rt_rtype_data; +uint8_t main_is_fn; + #endif //NATURE_TEST_RUNTIME_H diff --git a/utils/custom_links.h b/utils/custom_links.h index 2c98bbb5..7b46435b 100644 --- a/utils/custom_links.h +++ b/utils/custom_links.h @@ -55,6 +55,7 @@ typedef struct { #define SYMBOL_RTYPE_COUNT "rt_rtype_count" #define SYMBOL_RTYPE_DATA "rt_rtype_data" +#define SYMBOL_MAIN_IS_FN "main_is_fn" extern addr_t rt_fn_main_base; diff --git a/utils/type.c b/utils/type.c index da051165..172e4184 100644 --- a/utils/type.c +++ b/utils/type.c @@ -465,10 +465,11 @@ char *_type_format(type_t t) { if (t.kind == TYPE_FN) { if (t.fn) { + char *fn_prefix = t.fn->is_fx ? "fx" : "fn"; if (t.fn->is_errable) { - return dsprintf("fn(...):%s!", type_format(t.fn->return_type)); + return dsprintf("%s(...):%s!", fn_prefix, type_format(t.fn->return_type)); } else { - return dsprintf("fn(...):%s", type_format(t.fn->return_type)); + return dsprintf("%s(...):%s", fn_prefix, type_format(t.fn->return_type)); } } else { return "fn"; diff --git a/utils/type.h b/utils/type.h index 2c78a708..4de9f8cc 100644 --- a/utils/type.h +++ b/utils/type.h @@ -146,55 +146,56 @@ typedef enum { } type_ident_kind; static string type_kind_str[] = { - [TYPE_GC_ENV] = "env", - [TYPE_GC_ENV_VALUE] = "env_value", - [TYPE_GC_ENV_VALUES] = "env_values", - - [TYPE_ARR] = "arr", - - [TYPE_ANY] = "any", - [TYPE_UNION] = "union", - [TYPE_TAGGED_UNION] = "tagged_union", - - [TYPE_STRING] = "string", - [TYPE_RAW_STRING] = "raw_string", - [TYPE_BOOL] = "bool", - // [TYPE_FLOAT] = "float", - [TYPE_FLOAT32] = "f32", - [TYPE_FLOAT64] = "f64", - // [TYPE_INT] = "int", - // [TYPE_UINT] = "uint", - [TYPE_INT8] = "i8", - [TYPE_INT16] = "i16", - [TYPE_INT32] = "i32", - [TYPE_INT64] = "i64", - [TYPE_UINT8] = "u8", - [TYPE_UINT16] = "u16", - [TYPE_UINT32] = "u32", - [TYPE_UINT64] = "u64", - [TYPE_VOID] = "void", - [TYPE_UNKNOWN] = "unknown", - [TYPE_STRUCT] = "struct", // ast_struct_decl - [TYPE_IDENT] = "ident", - [TYPE_COROUTINE_T] = "coroutine_t", - [TYPE_CHAN] = "chan", - [TYPE_VEC] = "vec", - [TYPE_MAP] = "map", - [TYPE_SET] = "set", - [TYPE_TUPLE] = "tup", - [TYPE_FN] = "fn", - - // 底层类型 - [TYPE_FN_T] = "fn_t", - [TYPE_INTEGER_T] = "integer_t", - [TYPE_FLOATER_T] = "floater_t", - [TYPE_ALL_T] = "all_t", - - [TYPE_REF] = "ref", // ref - [TYPE_PTR] = "ptr", // ptr - [TYPE_ANYPTR] = "anyptr", // anyptr - [TYPE_NULL] = "null", - [TYPE_ENUM] = "enum", + [TYPE_GC_ENV] = "env", + [TYPE_GC_ENV_VALUE] = "env_value", + [TYPE_GC_ENV_VALUES] = "env_values", + + [TYPE_ARR] = "arr", + + [TYPE_ANY] = "any", + [TYPE_INTERFACE] = "interface", + [TYPE_UNION] = "union", + [TYPE_TAGGED_UNION] = "tagged_union", + + [TYPE_STRING] = "string", + [TYPE_RAW_STRING] = "raw_string", + [TYPE_BOOL] = "bool", + // [TYPE_FLOAT] = "float", + [TYPE_FLOAT32] = "f32", + [TYPE_FLOAT64] = "f64", + // [TYPE_INT] = "int", + // [TYPE_UINT] = "uint", + [TYPE_INT8] = "i8", + [TYPE_INT16] = "i16", + [TYPE_INT32] = "i32", + [TYPE_INT64] = "i64", + [TYPE_UINT8] = "u8", + [TYPE_UINT16] = "u16", + [TYPE_UINT32] = "u32", + [TYPE_UINT64] = "u64", + [TYPE_VOID] = "void", + [TYPE_UNKNOWN] = "unknown", + [TYPE_STRUCT] = "struct", // ast_struct_decl + [TYPE_IDENT] = "ident", + [TYPE_COROUTINE_T] = "coroutine_t", + [TYPE_CHAN] = "chan", + [TYPE_VEC] = "vec", + [TYPE_MAP] = "map", + [TYPE_SET] = "set", + [TYPE_TUPLE] = "tup", + [TYPE_FN] = "fn", + + // 底层类型 + [TYPE_FN_T] = "fn_t", + [TYPE_INTEGER_T] = "integer_t", + [TYPE_FLOATER_T] = "floater_t", + [TYPE_ALL_T] = "all_t", + + [TYPE_REF] = "ref", // ref + [TYPE_PTR] = "ptr", // ptr + [TYPE_ANYPTR] = "anyptr", // anyptr + [TYPE_NULL] = "null", + [TYPE_ENUM] = "enum", }; typedef struct { @@ -467,6 +468,7 @@ struct type_fn_t { list_t *param_types; // type_t bool is_rest; bool is_errable; + bool is_fx; bool is_tpl; int self_kind; }; @@ -475,13 +477,13 @@ struct type_fn_t { // 类型对应的数据在内存中的存储形式 --- start // 部分类型的数据(复合类型)只能在堆内存中存储 - typedef struct { uint8_t *data; int64_t length; // 实际占用的位置的大小 int64_t capacity; // 预先申请的容量大小 int64_t element_size; int64_t hash; + void *allocator; } n_vec_t, n_string_t; // 通过 gc malloc 申请 @@ -722,7 +724,8 @@ static inline bool type_is_ident(type_t *t) { return false; } - return t->ident_kind == TYPE_IDENT_DEF || t->ident_kind == TYPE_IDENT_INTERFACE || t->ident_kind == TYPE_IDENT_TAGGER_UNION || t->ident_kind == TYPE_IDENT_UNKNOWN; + return t->ident_kind == TYPE_IDENT_DEF || t->ident_kind == TYPE_IDENT_INTERFACE || t->ident_kind == + TYPE_IDENT_TAGGER_UNION || t->ident_kind == TYPE_IDENT_UNKNOWN; } static inline type_t type_ident_new(char *ident, type_ident_kind kind) { @@ -785,7 +788,8 @@ static inline bool is_number(type_kind kind) { } static inline storage_kind_t type_storage_kind(type_t t) { - if (is_number(t.kind) || t.kind == TYPE_BOOL || t.kind == TYPE_ANYPTR || t.kind == TYPE_ENUM || t.kind == TYPE_VOID) { + if (is_number(t.kind) || t.kind == TYPE_BOOL || t.kind == TYPE_ANYPTR || t.kind == TYPE_ENUM || t.kind == + TYPE_VOID) { return STORAGE_KIND_DIR; } @@ -932,11 +936,13 @@ static inline list_t *type_abi_struct(type_t t) { type_t cap_type = type_kind_new(TYPE_INT64); type_t elem_size_type = type_kind_new(TYPE_INT64); type_t hash_type = type_kind_new(TYPE_INT64); + type_t allocator = type_kind_new(TYPE_ANYPTR); ct_list_push(result, &data_ptr); ct_list_push(result, &len_type); ct_list_push(result, &cap_type); ct_list_push(result, &elem_size_type); ct_list_push(result, &hash_type); + ct_list_push(result, &allocator); return result; } @@ -1019,7 +1025,8 @@ static inline bool is_abi_struct_like(type_t t) { } static inline bool is_impl_builtin_type(type_kind kind) { - return is_number(kind) || kind == TYPE_BOOL || kind == TYPE_MAP || kind == TYPE_SET || kind == TYPE_VEC || kind == TYPE_CHAN || + return is_number(kind) || kind == TYPE_BOOL || kind == TYPE_MAP || kind == TYPE_SET || kind == TYPE_VEC || kind == + TYPE_CHAN || kind == TYPE_STRING || kind == TYPE_COROUTINE_T; }