diff --git a/api/fn.hpp b/api/fn.hpp index 2c61a3318..3db522f5d 100644 --- a/api/fn.hpp +++ b/api/fn.hpp @@ -35,7 +35,89 @@ namespace jule { - // std::function wrapper of JuleC. + // Anonymous function / closure wrapper of JuleC. + template + struct Fn2 + { + public: + Ret (*f)(jule::Ptr, Args...); + jule::Ptr ctx; // Closure ctx. + void (*ctxHandler)(jule::Ptr &alloc) = nullptr; + + Fn2(void) = default; + Fn2(const Fn2 &) = default; + Fn2(std::nullptr_t) noexcept : Fn2() {} + + Fn2(Ret (*f)(jule::Ptr, Args...)) noexcept + { + this->f = f; + } + + ~Fn2(void) noexcept + { + this->f = nullptr; + if (this->ctxHandler) + { + this->ctxHandler(this->ctx); + this->ctxHandler = nullptr; + this->ctx.ref = nullptr; // Disable GC for allocation. + this->ctx = nullptr; // Assign to nullptr safely. + } + } + + template + Ret call( +#ifndef __JULE_ENABLE__PRODUCTION + const char *file, +#endif + Args... args) + { +#ifndef __JULE_DISABLE__SAFETY + if (this->f == nullptr) +#ifndef __JULE_ENABLE__PRODUCTION + jule::panic((std::string(__JULE_ERROR__INVALID_MEMORY) + "\nfile: ") + file); +#else + jule::panic(__JULE_ERROR__INVALID_MEMORY); +#endif // PRODUCTION +#endif // SAFETY + return this->f(this->ctx, args...); + } + + inline auto operator()(Args... args) + { +#ifndef __JULE_ENABLE__PRODUCTION + return this->call("/api/fn.hpp", args...); +#else + return this->call(args...); +#endif + } + + inline Fn2 &operator=(std::nullptr_t) noexcept + { + this->f = nullptr; + return *this; + } + + constexpr jule::Bool operator==(std::nullptr_t) const noexcept + { + return this->f == nullptr; + } + + constexpr jule::Bool operator!=(std::nullptr_t) const noexcept + { + return !this->operator==(nullptr); + } + + friend std::ostream &operator<<(std::ostream &stream, + const Fn2 &f) noexcept + { + if (f == nullptr) + return (stream << ""); + return (stream << (void *)f.f); + } + }; + + // Anonymous function / closure wrapper of JuleC. template struct Fn { @@ -117,6 +199,15 @@ namespace jule } }; + template + jule::Fn2 __new_closure2(void *fn, jule::Ptr ctx, void (*ctxHandler)(jule::Ptr &)) noexcept + { + jule::Fn2 fn2((Ret(*)(jule::Ptr, Args...))fn); + fn2.ctx = std::move(ctx); + fn2.ctxHandler = ctxHandler; + return fn2; + } + static jule::Uint __page_size = __JULE_ASSUMED_PAGE_SIZE; #if defined(ARCH_AMD64) diff --git a/src/julec/obj/cxx/expr.jule b/src/julec/obj/cxx/expr.jule index 8ecfe7e1b..5efb42dc8 100644 --- a/src/julec/obj/cxx/expr.jule +++ b/src/julec/obj/cxx/expr.jule @@ -642,6 +642,16 @@ impl exprCoder { } } self.pushCallInf(m) + if m.Func.AsAnon && !m.Func.Anon { + // Function used as anonymous. + // So pass nullptr to ctx parameter. + // Do not pass nullptr if function is anonymous, + // beacause it stores ctx data internally and it will pass. + self.oc.write("nullptr") + if len(m.Args) > 0 { + self.oc.write(", ") + } + } mut locinfo := false if !m.Func.IsBuiltin() && len(m.Func.Decl.Params) > 0 && m.Func.Decl.Params[0].IsSelf() { match type m.Expr { @@ -928,7 +938,7 @@ impl exprCoder { fn anonFunc(mut &self, mut m: &AnonFnExprModel) { ident := self.oc.pushAnonFn(m) - self.oc.write("jule::__new_closure<") + self.oc.write("jule::__new_closure2<") self.oc.tc.anonFunc(self.oc.Buf, m.Func) self.oc.write(">((void*)") self.oc.write(ident) diff --git a/src/julec/obj/cxx/object.jule b/src/julec/obj/cxx/object.jule index e4b7ea3cd..0b7eb868e 100644 --- a/src/julec/obj/cxx/object.jule +++ b/src/julec/obj/cxx/object.jule @@ -45,6 +45,7 @@ use std::time::{Time} // Data offset of empty trait. const emptyTraitOffset = 0x0 +const ctxParamIdent = "__f_ctx" const anonFnCtxSuffix = "_ctx" // Anon fn identifier suffix for ctx struct identifier. const anonFnCtxHandlerSuffix = anonFnCtxSuffix + "_handler" // Anon fn identifier suffix for ctx allocation handler. const anyTypeIdent = "__jule_any_type" @@ -849,23 +850,6 @@ impl ObjectCoder { } } - fn paramsDecls(mut &self, mut ¶ms: []&ParamIns) { - if len(params) == 0 { - self.write("(void)") - ret - } - - self.write("(") - for (i, mut p) in params { - self.tc.paramIns(self.Buf, p) - if len(params)-i > 1 { - self.write(", ") - } - } - - self.write(")") - } - // The ident parameter means this function is anon, mostly. // But this parameter not only for anonymous functions. // It also useable as custom identifiers for functions. @@ -891,7 +875,7 @@ impl ObjectCoder { fn funcDeclIns(mut &self, mut &f: &FnIns, ptr: bool) { self.indent() self.funcHead(self.Buf, f, ptr, "") - self.paramsDecls(f.Params) + self.paramsIns(self.Buf, f) self.write(";\n") } @@ -988,15 +972,21 @@ impl ObjectCoder { identCoder.param(buf, p.Decl) } - fn paramsIns(mut &self, mut &buf: StrBuilder, mut ¶ms: []&ParamIns) { - if len(params) == 0 { + fn paramsIns(mut &self, mut &buf: StrBuilder, mut &f: &FnIns) { + if !f.AsAnon && len(f.Params) == 0 { buf.WriteStr("(void)") ret } buf.WriteByte('(') - for (i, mut p) in params { + if f.AsAnon { + buf.WriteStr(ctxParamType + " " + ctxParamIdent) + if len(f.Params) > 0 { + buf.WriteStr(", ") + } + } + for (i, mut p) in f.Params { self.paramIns(buf, p) - if len(params)-i > 1 { + if len(f.Params)-i > 1 { buf.WriteStr(", ") } } @@ -1054,13 +1044,13 @@ impl ObjectCoder { fn anonFuncInsDecl(mut &self, mut &m: &AnonFnExprModel, ident: str) { self.funcHead(self.anonObj, m.Func, false, ident) - self.paramsIns(self.anonObj, m.Func.Params) + self.paramsIns(self.anonObj, m.Func) self.anonObj.WriteByte(';') } fn anonFuncIns(mut &self, mut &m: &AnonFnExprModel, ident: str) { self.funcHead(self.Buf, m.Func, false, ident) - self.paramsIns(self.Buf, m.Func.Params) + self.paramsIns(self.Buf, m.Func) self.write(" ") self.sc.anonFuncScope(m, ident) if m.Func.Scope != nil { @@ -1070,7 +1060,7 @@ impl ObjectCoder { fn funcIns(mut &self, mut &f: &FnIns) { self.funcHead(self.Buf, f, false, "") - self.paramsIns(self.Buf, f.Params) + self.paramsIns(self.Buf, f) self.write(" ") self.sc.funcScope(f) if f.Scope != nil { @@ -1384,7 +1374,6 @@ impl ObjectCoder { fn end(mut &self) { self.write(`int main(int argc, char *argv[], char *envp[]) { - jule::__closure_init(); jule::setup_argv(argc, argv); jule::setup_envp(envp); diff --git a/src/julec/obj/cxx/scope.jule b/src/julec/obj/cxx/scope.jule index aad12fd9a..ef5da3049 100644 --- a/src/julec/obj/cxx/scope.jule +++ b/src/julec/obj/cxx/scope.jule @@ -46,6 +46,7 @@ use std::jule::sema::{ } use std::strings::{StrBuilder} +const closureCtxIdent = "__jule_closure_ctx" const matchExpr = "_match_expr" const resultName = "__jule_func_result" const assignResultName = "__jule_assign_result" @@ -1007,10 +1008,11 @@ impl scopeCoder { // Get ctx. self.oc.indent() + self.oc.write(typeCoder.Ptr + "<") self.oc.write(ident) - self.oc.write(anonFnCtxSuffix + " *__jule_closure_ctx = (") + self.oc.write(anonFnCtxSuffix + "> " + closureCtxIdent + " = " + ctxParamIdent + ".as<") self.oc.write(ident) - self.oc.write(anonFnCtxSuffix + "*)jule::__closure_get_ctx();\n") + self.oc.write(anonFnCtxSuffix + ">();\n") self.commonFuncScope(m.Func) @@ -1055,7 +1057,7 @@ fn isIterCopyOptimizable(&expr: &Data, &v: &Var): bool { fn captureVarHandling(mut &oc: &ObjectCoder, mut &m: &AnonFnExprModel, mut &v: &Var): bool { for _, cv in m.Captured { if cv == v { - oc.write("__jule_closure_ctx->") + oc.write(closureCtxIdent + ".alloc->") identCoder.var(oc.Buf, v) ret true } diff --git a/src/julec/obj/cxx/type.jule b/src/julec/obj/cxx/type.jule index 6ff1c7b5e..f91a027ca 100644 --- a/src/julec/obj/cxx/type.jule +++ b/src/julec/obj/cxx/type.jule @@ -29,6 +29,8 @@ use std::jule::sema::{ use types for std::jule::types use std::strings::{StrBuilder} +const ctxParamType = typeCoder.Ptr + "<" + typeCoder.Uintptr + ">" + struct customType { kind: str } @@ -57,7 +59,7 @@ impl typeCoder { const Slice = "jule::Slice" const Trait = "jule::Trait" const Array = "jule::Array" - const Fn = "jule::Fn" + const Fn = "jule::Fn2" const Bool = "jule::Bool" const Int = "jule::Int" const Uintptr = "jule::Uintptr" diff --git a/std/jule/sema/eval.jule b/std/jule/sema/eval.jule index 7dcf964a6..dd17c4931 100644 --- a/std/jule/sema/eval.jule +++ b/std/jule/sema/eval.jule @@ -2914,6 +2914,7 @@ impl Eval { if ins == nil { ret nil } + ins.AsAnon = true mut captured := make([]&Var, 0) match type self.lookup { | &scopeChecker: @@ -3019,9 +3020,10 @@ impl Eval { } if len(f.Generics) != len(f.Decl.Generics) { self.s.pushErr(expr.Token, LogMsg.HasGenerics) - } - if !f.Decl.Statically && f.Decl.IsMethod() { + } else if !f.Decl.Statically && f.Decl.IsMethod() { self.s.pushErr(expr.Token, LogMsg.MethodNotInvoked) + } else { + f.AsAnon = true } } diff --git a/std/jule/sema/fn.jule b/std/jule/sema/fn.jule index 02fe65eaa..cc1669417 100644 --- a/std/jule/sema/fn.jule +++ b/std/jule/sema/fn.jule @@ -201,6 +201,7 @@ struct FnIns { Scope: &Scope Refers: &ReferenceStack Anon: bool + AsAnon: bool // Whether this function instance used as anonymous function. caller: builtinCaller reloaded: bool