diff --git a/api/any.hpp b/api/any.hpp index 9ce1916fe..aac8b8a0f 100644 --- a/api/any.hpp +++ b/api/any.hpp @@ -13,18 +13,12 @@ #include #include "str.hpp" -#include "builtin.hpp" -#include "ptr.hpp" namespace jule { - - // Built-in any type. - class Any; - class Any { - private: + public: template struct DynamicType { @@ -135,7 +129,7 @@ namespace jule template void __assign(const T &expr) noexcept { - T *alloc = new (std::nothrow) T; + auto alloc = new (std::nothrow) T; if (!alloc) jule::panic(__JULE_ERROR__MEMORY_ALLOCATION_FAILED "\nruntime: memory allocation failed for heap data of type any"); @@ -149,7 +143,6 @@ namespace jule { if (this->data) this->type->dealloc(this->data); - this->type = nullptr; this->data = nullptr; } @@ -167,7 +160,7 @@ namespace jule } template - Any& operator=(const T &expr) noexcept + Any &operator=(const T &expr) noexcept { jule::Any::Type *type = jule::Any::new_type(); if (this->type != nullptr && this->type == type) @@ -181,7 +174,7 @@ namespace jule return *this; } - Any& operator=(const jule::Any &src) noexcept + Any &operator=(const jule::Any &src) noexcept { // Assignment to itself. if (this->data != nullptr && this->data == src.data) @@ -192,7 +185,7 @@ namespace jule return *this; } - inline Any& operator=(const std::nullptr_t) noexcept + inline Any &operator=(const std::nullptr_t) noexcept { this->dealloc(); return *this; diff --git a/api/derive/clone.hpp b/api/derive/clone.hpp index 0af8f1857..7dcd0b3aa 100644 --- a/api/derive/clone.hpp +++ b/api/derive/clone.hpp @@ -37,6 +37,8 @@ namespace jule jule::Ptr clone(const jule::Ptr &r); template jule::Trait clone(const jule::Trait &t); + template + jule::Trait2 clone(const jule::Trait2 &t); template jule::Fn clone(const jule::Fn &fn) noexcept; template @@ -91,8 +93,7 @@ namespace jule { if (r == nullptr) return r; - - return jule::Ptr::make(jule::clone(r.operator T())); + return jule::Ptr::make(jule::clone(*r)); } template @@ -103,6 +104,17 @@ namespace jule return t; } + template + jule::Trait2 clone(const jule::Trait2 &t) { + if (t == nullptr) + return t; + jule::Trait2 clone; + clone.type = t.type; + clone.type_offset = t.type_offset; + clone.data = jule::Ptr::make(t.type->clone(t.data.alloc)); + return clone; + } + template jule::Fn clone(const jule::Fn &fn) noexcept { diff --git a/api/ptr.hpp b/api/ptr.hpp index 9e80b2d5c..dbc1a3c1a 100644 --- a/api/ptr.hpp +++ b/api/ptr.hpp @@ -224,6 +224,19 @@ namespace jule return *this->alloc; } + template + jule::Ptr as(void) const noexcept + { + jule::Ptr ptr; + ptr.ref = this->ref; +#ifndef __JULE_DISABLE__REFERENCE_COUNTING + if (this->ref) + this->add_ref(); +#endif + ptr.alloc = reinterpret_cast(this->alloc); + return ptr; + } + inline T *operator->(void) const noexcept { return this->ptr( @@ -272,7 +285,7 @@ namespace jule } } - Ptr& operator=(const jule::Ptr &src) noexcept + Ptr &operator=(const jule::Ptr &src) noexcept { // Assignment to itself. if (this->alloc != nullptr && this->alloc == src.alloc) diff --git a/api/slice.hpp b/api/slice.hpp index f04976afa..9f30d791b 100644 --- a/api/slice.hpp +++ b/api/slice.hpp @@ -210,8 +210,8 @@ namespace jule *(this->_slice + i) = def; } - using Iterator = Item*; - using ConstIterator = const Item*; + using Iterator = Item *; + using ConstIterator = const Item *; constexpr Iterator begin(void) noexcept { @@ -323,10 +323,7 @@ namespace jule { jule::Slice _new; _new.alloc_new(this->_len + 1, (this->_len + 1) << 1); - std::move( - this->_slice, - this->_slice + this->_len, - _new._slice); + std::move(this->_slice, this->_slice + this->_len, _new._slice); *(_new._slice + this->_len) = item; this->operator=(_new); @@ -441,7 +438,7 @@ namespace jule index); } - Slice& operator=(const jule::Slice &src) noexcept + Slice &operator=(const jule::Slice &src) noexcept { // Assignment to itself. if (this->data.alloc != nullptr && this->data.alloc == src.data.alloc) @@ -457,7 +454,7 @@ namespace jule return *this; } - inline Slice& operator=(const std::nullptr_t) noexcept + inline Slice &operator=(const std::nullptr_t) noexcept { this->dealloc(); return *this; diff --git a/api/trait.hpp b/api/trait.hpp index f576b3289..3c5bf6ad0 100644 --- a/api/trait.hpp +++ b/api/trait.hpp @@ -17,7 +17,6 @@ namespace jule { - // Wrapper structure for traits. template struct Trait; @@ -223,13 +222,13 @@ namespace jule ); } - inline jule::Trait& operator=(const std::nullptr_t) noexcept + inline jule::Trait &operator=(const std::nullptr_t) noexcept { this->dealloc(); return *this; } - inline jule::Trait& operator=(const jule::Trait &src) noexcept + inline jule::Trait &operator=(const jule::Trait &src) noexcept { // Assignment to itself. if (this->data.alloc != nullptr && this->data.alloc == src.data.alloc) @@ -266,7 +265,280 @@ namespace jule return stream << src.data.alloc; } }; +} // namespace jule + +namespace jule +{ + template + struct Trait2 + { + public: + template + struct DynamicType + { + public: + static jule::Uintptr *clone(jule::Uintptr *ptr) noexcept + { + return reinterpret_cast( + new (std::nothrow) T(*reinterpret_cast(ptr))); + } + + static void dealloc(jule::Ptr &alloc) noexcept + { + jule::Ptr ptr; + ptr.alloc = reinterpret_cast(alloc.alloc); + ptr.ref = alloc.ref; + ptr.dealloc(); + } + }; + + struct Type + { + public: + void (*dealloc)(jule::Ptr &alloc); + jule::Uintptr *(*clone)(jule::Uintptr *ptr); + }; + + template + static jule::Trait2::Type *new_type(void) noexcept + { + using type = typename std::decay::DynamicType>::type; + static jule::Trait2::Type table = { + .dealloc = type::dealloc, + .clone = type::clone, + }; + return &table; + } + + public: + mutable jule::Ptr data; + mutable jule::Trait2::Type *type = nullptr; + mutable const char *type_id; + jule::Uint type_offset = 0; + + Trait2(void) = default; + Trait2(std::nullptr_t) : Trait2() {} + + template + Trait2(const T &data, const jule::Uint &type_offset) noexcept + { + this->type_offset = type_offset; + this->type = jule::Trait2::new_type(); + this->type_id = typeid(T).name(); + T *alloc = new (std::nothrow) T; + if (!alloc) + jule::panic(__JULE_ERROR__MEMORY_ALLOCATION_FAILED "\nfile: /api/trait.hpp"); + + *alloc = data; +#ifdef __JULE_DISABLE__REFERENCE_COUNTING + this->data = jule::Ptr::make(reinterpret_cast(alloc), nullptr); +#else + this->data = jule::Ptr::make(reinterpret_cast(alloc)); +#endif + } + + template + Trait2(const jule::Ptr &ref, const jule::Uint &type_offset) noexcept + { + this->type_id = typeid(jule::Ptr).name(); + this->type_offset = type_offset; + this->type = jule::Trait2::new_type(); + this->data = ref.template as(); + } + + Trait2(const jule::Trait2 &src) noexcept + { + this->__get_copy(src); + } + + ~Trait2(void) noexcept + { + this->dealloc(); + } + + void dealloc(void) const noexcept + { + if (this->type) + this->type->dealloc(this->data); + this->data.ref = nullptr; + this->data.alloc = nullptr; + this->type = nullptr; + this->type_id = nullptr; + } + + // Copy content from source. + void __get_copy(const jule::Trait2 &src) noexcept + { + this->data = src.data; + this->type_offset = src.type_offset; + this->type = src.type; + this->type_id = src.type_id; + } + + inline void must_ok( +#ifndef __JULE_ENABLE__PRODUCTION + const char *file +#else + void +#endif + ) const noexcept + { + if (this->operator==(nullptr)) + { +#ifndef __JULE_ENABLE__PRODUCTION + std::string error = __JULE_ERROR__INVALID_MEMORY "\nfile: "; + error += file; + jule::panic(error); +#else + jule::panic(__JULE_ERROR__INVALID_MEMORY "\nfile: /api/trait.hpp"); +#endif + } + } + + template + inline jule::Bool type_is(void) const noexcept + { + if (this->operator==(nullptr)) + return false; + return std::strcmp(this->type_id, typeid(T).name()) == 0; + } + + template + inline T *safe_ptr( +#ifndef __JULE_ENABLE__PRODUCTION + const char *file +#else + void +#endif + ) + { +#ifndef __JULE_DISABLE__SAFETY + this->must_ok( +#ifndef __JULE_ENABLE__PRODUCTION + file +#endif + ); +#endif + return reinterpret_cast(this->data.alloc); + } + + template + inline T cast( +#ifndef __JULE_ENABLE__PRODUCTION + const char *file +#else + void +#endif + ) noexcept + { +#ifndef __JULE_DISABLE__SAFETY + this->must_ok( +#ifndef __JULE_ENABLE__PRODUCTION + file +#endif + ); + if (std::strcmp(this->type_id, typeid(T).name()) != 0) + { +#ifndef __JULE_ENABLE__PRODUCTION + std::string error = __JULE_ERROR__INCOMPATIBLE_TYPE "\nruntime: trait casted to incompatible type\nfile: "; + error += file; + jule::panic(error); +#else + jule::panic(__JULE_ERROR__INCOMPATIBLE_TYPE "\nruntime: trait casted to incompatible type"); +#endif + } +#endif + return *static_cast(this->data.alloc); + } + + template + jule::Ptr cast_ptr( +#ifndef __JULE_ENABLE__PRODUCTION + const char *file +#else + void +#endif + ) noexcept + { +#ifndef __JULE_DISABLE__SAFETY + this->must_ok( +#ifndef __JULE_ENABLE__PRODUCTION + file +#endif + ); + if (std::strcmp(this->type_id, typeid(jule::Ptr).name()) != 0) + { +#ifndef __JULE_ENABLE__PRODUCTION + std::string error = __JULE_ERROR__INCOMPATIBLE_TYPE "\nruntime: trait casted to incompatible type\nfile: "; + error += file; + jule::panic(error); +#else + jule::panic(__JULE_ERROR__INCOMPATIBLE_TYPE "\nruntime: trait casted to incompatible type"); +#endif + } +#endif + return this->data.template as(); + } + template + inline operator T(void) noexcept + { + return this->cast( +#ifndef __JULE_ENABLE__PRODUCTION + "/api/trait.hpp" +#endif + ); + } + + template + inline operator jule::Ptr(void) noexcept + { + return this->cast_ptr( +#ifndef __JULE_ENABLE__PRODUCTION + "/api/trait.hpp" +#endif + ); + } + + inline jule::Trait2 &operator=(const std::nullptr_t) noexcept + { + this->dealloc(); + return *this; + } + + inline jule::Trait2 &operator=(const jule::Trait2 &src) noexcept + { + this->dealloc(); + this->__get_copy(src); + return *this; + } + + constexpr jule::Bool operator==(const jule::Trait2 &src) const noexcept + { + return this->data.alloc == src.data.alloc; + } + + constexpr jule::Bool operator!=(const jule::Trait2 &src) const noexcept + { + return !this->operator==(src); + } + + constexpr jule::Bool operator==(std::nullptr_t) const noexcept + { + return this->data.alloc == nullptr; + } + + constexpr jule::Bool operator!=(std::nullptr_t) const noexcept + { + return !this->operator==(nullptr); + } + + friend inline std::ostream &operator<<(std::ostream &stream, + const jule::Trait2 &src) noexcept + { + return stream << (void *)src.data.alloc; + } + }; } // namespace jule #endif // #ifndef __JULE_TRAIT_HPP diff --git a/src/julec/obj/cxx/expr.jule b/src/julec/obj/cxx/expr.jule index 007237bfa..64748c16c 100644 --- a/src/julec/obj/cxx/expr.jule +++ b/src/julec/obj/cxx/expr.jule @@ -347,24 +347,15 @@ impl ExprCoder { ret obj } - fn alloc_structure_call(mut self, mut &s: &StructIns, &lit: str): str { - let mut obj = "jule::new_struct" - if s.decl.has_ref_accessible() { - obj += "_ptr" - } - obj += "<" - obj += IdentCoder.structure_ins(s) + fn alloc_structure(mut self, mut m: &AllocStructLitExprModel): str { + let mut obj = "jule::new_ptr<" + obj += IdentCoder.structure_ins(m.lit.strct) obj += ">(" - obj += lit + obj += self.structure_lit(m.lit) obj += ")" ret obj } - fn alloc_structure(mut self, mut m: &AllocStructLitExprModel): str { - let lit = "new (std::nothrow)" + self.structure_lit(m.lit) - ret self.alloc_structure_call(m.lit.strct, lit) - } - fn casting(mut self, mut m: &CastingExprModel): str { let mut obj = "" match { @@ -400,6 +391,13 @@ impl ExprCoder { obj += self.oc.loc_info(m.token) obj += "\")" } + | m.kind.trt() != nil: + obj += TypeCoder.kind(m.kind) + obj += "(" + obj += self.expr(m.expr) + obj += ", " + obj += conv::itoa(self.oc.find_type_offset(m.kind.trt(), m.expr_kind)) + obj += ")" |: obj += "static_cast<" obj += TypeCoder.kind(m.kind) @@ -427,9 +425,13 @@ impl ExprCoder { match type expr { | &FnIns: ret self.func_ins((&FnIns)(expr)) - |: - ret self.model(expr) + | &StructSubIdentExprModel: + let mut ssie = (&StructSubIdentExprModel)(expr) + if ssie.method != nil { + ret self.func_ins(ssie.method) + } } + ret self.model(expr) } fn push_call_inf(mut self, mut &obj: str, &m: &FnCallExprModel) { @@ -473,7 +475,49 @@ impl ExprCoder { } } self.push_call_inf(obj, m) + let mut locinfo = false + if !m.func.is_builtin() && m.func.decl.params.len > 0 && m.func.decl.params[0].is_self() { + match type m.expr { + | &StructSubIdentExprModel: + let mut ssie = (&StructSubIdentExprModel)(m.expr) + match { + | m.func.decl.params[0].is_ref(): + obj += self.model(ssie.expr) + | ssie.expr_kind.sptr() != nil: + obj += self.model(ssie.expr) + obj += ".ptr(" + if !env::PRODUCTION { + obj += "\"" + obj += self.oc.loc_info(m.token) + obj += "\"" + } + obj += ")" + |: + if ssie.expr.kind.strct() != nil { + // Add address taking operation for non-pointers. + obj += "&" + } + obj += self.model(ssie.expr) + } + if m.args.len > 0 { + obj += ", " + } + | &TraitSubIdentExprModel: + obj += self.model((&TraitSubIdentExprModel)(m.expr).expr) + if !env::PRODUCTION { + locinfo = true + } + if m.args.len > 0 { + obj += ", " + } + } + } obj += self.args(m.args) + if locinfo { + obj += ", \"" + obj += self.oc.loc_info(m.token) + obj += "\"" + } obj += ")" if m.is_co { @@ -637,25 +681,32 @@ impl ExprCoder { } fn trait_sub(mut self, mut m: &TraitSubIdentExprModel): str { - let mut obj = self.model(m.expr) - obj += ".get(" - if !env::PRODUCTION { - obj += "\"" - obj += self.oc.loc_info(m.token) - obj += "\"" - } - obj += ")._method_" - obj += m.ident + let mut obj = IdentCoder.trait_decl(m.trt) + obj += "_mptr_data" + obj += "[(" + obj += self.model(m.expr) + obj += ").type_offset]." + obj += IdentCoder.func(m.method) ret obj } fn structure_sub(mut self, mut m: &StructSubIdentExprModel): str { let mut obj = self.model(m.expr) - obj += "." if m.field != nil { + if m.expr_kind.ptr() != nil { + obj += "->" + } else if m.expr_kind.sptr() != nil { + obj += ".get(" + if !env::PRODUCTION { + obj += "\"" + obj += self.oc.loc_info(m.token) + obj += "\"" + } + obj += ")." + } else { + obj += "." + } obj += IdentCoder.field(m.field.decl) - } else { - obj += IdentCoder.func_ins(m.method) } ret obj } @@ -666,7 +717,20 @@ impl ExprCoder { fn common_sub(mut self, mut m: &CommonSubIdentExprModel): str { let mut obj = self.model(m.expr) - obj += "." + match { + | m.expr_kind.ptr() != nil: + obj += "->" + | m.expr_kind.sptr() != nil: + obj += ".get(" + if !env::PRODUCTION { + obj += "\n" + obj += self.oc.loc_info(m.token) + obj += "\n" + } + obj += ")." + |: + obj += "." + } obj += m.ident ret obj } @@ -728,19 +792,6 @@ impl ExprCoder { } fn new_call(mut self, mut m: &BuiltinNewCallExprModel): str { - if m.kind.strct() != nil { - let mut s = m.kind.strct() - let mut lit = "new (std::nothrow) " - lit += TypeCoder.structure_ins(s) - if m.init != nil { - lit += "{" - lit += self.expr(m.init) - lit += "}" - } else { - lit += "()" - } - ret self.alloc_structure_call(s, lit) - } let mut obj = "jule::new_ptr<" obj += TypeCoder.kind(m.kind) obj += ">(" @@ -895,10 +946,7 @@ impl ExprCoder { } fn structure_static(self, mut m: &StructStaticIdentExprModel): str { - let mut obj = IdentCoder.structure_ins(m.structure) - obj += "::" - obj += IdentCoder.func_ins(m.method) - ret obj + ret IdentCoder.func_ins(m.method) } fn integrated_to_str(mut self, mut m: &IntegratedToStrExprModel): str { diff --git a/src/julec/obj/cxx/ident.jule b/src/julec/obj/cxx/ident.jule index 03de5c80f..0eda68aa8 100644 --- a/src/julec/obj/cxx/ident.jule +++ b/src/julec/obj/cxx/ident.jule @@ -24,6 +24,8 @@ const INIT_CALLER_IDENT = "__jule_call_initializers" struct IdentCoder {} impl IdentCoder { + const Self = "_self_" + // Returns specified identifer as JuleC identifer. // Equavalents: "JULEC_ID(" + ident + ")" of JuleC API. static fn to_ident(ident: str): str { @@ -72,10 +74,12 @@ impl IdentCoder { | f.ident == ENTRY_POINT: ret "entry_point" | f.is_method(): + let mut obj = IdentCoder.to_out(f.ident, uintptr(f)) if f.statically { - ret "_static_method_" + f.ident + obj = "static_" + obj + ret obj } - ret "_method_" + f.ident + ret obj |: ret IdentCoder.to_out(f.ident, uintptr(f)) } @@ -113,6 +117,9 @@ impl IdentCoder { if is_anon_ident(p.ident) || is_ignore_ident(p.ident) { ret "" } + if p.is_self() { + ret IdentCoder.Self + } ret IdentCoder.to_local(p.token.row, p.token.column, p.ident) } @@ -159,10 +166,10 @@ impl IdentCoder { | v.ident == TokenKind.Error: ret "except.error" | v.ident == TokenKind.Self: - if v.kind.kind.sptr() != nil { - ret "this->self" + if v.kind.kind.sptr() == nil { + ret "(*" + IdentCoder.Self + ")" } - ret "(*this)" + ret IdentCoder.Self | v.scope != nil: ret IdentCoder.to_local(v.token.row, v.token.column, v.ident) |: diff --git a/src/julec/obj/cxx/object.jule b/src/julec/obj/cxx/object.jule index da65ee912..c2fb64d97 100644 --- a/src/julec/obj/cxx/object.jule +++ b/src/julec/obj/cxx/object.jule @@ -35,6 +35,10 @@ use std::jule::sema::{ StructIns, Fn, FnIns, + TypeKind, + Prim, + Sptr, + TypeSymbol, } use path for std::fs::path use strings for std::strings @@ -45,6 +49,12 @@ pub struct SerializationInfo { pub compiler_command: str } +struct TraitHash { + t: &Trait + s: &StructIns + i: int +} + pub struct ObjectCoder { ir: &IR info: SerializationInfo @@ -52,6 +62,12 @@ pub struct ObjectCoder { // Current indention. indent_buffer: str + trait_declarations: str + trait_wrappers: str + trait_data: str + trait_data_t: str + trait_map: []&TraitHash + ec: &ExprCoder sc: &ScopeCoder } @@ -83,6 +99,23 @@ impl ObjectCoder { ret self.indent_buffer } + fn find_type_offset(self, t: &Trait, mut k: &TypeKind): int { + let mut s: &StructIns = nil + if k.sptr() != nil { + k = k.sptr().elem + } + if k.strct() == nil { + ret -1 + } + s = k.strct() + for _, hash in self.trait_map { + if hash.t == t && hash.s == s { + ret hash.i + } + } + ret -1 + } + // Returns location information of token as cstr bytes. fn loc_info(self, &t: Token): str { let mut loc = t.file.path @@ -154,17 +187,19 @@ impl ObjectCoder { // Generates C++ code of parameters. fn params(mut self, mut ¶ms: []&Param): str { - match { - | params.len == 0: - ret "(void)" - | params.len == 1 && params[0].is_self(): + if params.len == 0 { ret "(void)" } let mut obj = "(" for (_, mut p) in params { - if !p.is_self() { - obj += self.param(p) + "," + if p.is_self() { + if p.is_ref() { + obj += self.param(p) + } + } else { + obj += self.param(p) } + obj += "," } // Remove comma. @@ -176,15 +211,12 @@ impl ObjectCoder { match { | params.len == 0: ret "(void)" - | params.len == 1 && params[0].decl.is_self(): - ret "(void)" } let mut obj = "(" for (_, mut p) in params { - if !p.decl.is_self() { - obj += self.param_ins(p) + "," - } + obj += self.param_ins(p) + obj += "," } // Remove comma. @@ -194,19 +226,14 @@ impl ObjectCoder { // Generates C++ declaration code of parameters. fn params_decls(mut self, mut ¶ms: []&ParamIns): str { - match { - | params.len == 0: - ret "(void)" - | params.len == 1 && params[0].decl.is_self(): + if params.len == 0 { ret "(void)" } let mut obj = "(" for (_, mut p) in params { - if !p.decl.is_self() { - obj += TypeCoder.param_ins(p) - obj += "," - } + obj += TypeCoder.param_ins(p) + obj += "," } // Remove comma. @@ -214,86 +241,183 @@ impl ObjectCoder { ret obj + ")" } - // Generates C++ code of trait. - fn trait_def(mut self, mut &t: &Trait): str { - const INDENTION = "\t" - let outid = IdentCoder.trait_decl(t) - - let mut obj = "struct " - obj += outid - obj += " {\n" - obj += INDENTION - obj += "virtual ~" - obj += outid - obj += "(void) {}\n\n" - for (_, mut f) in t.methods { - obj += INDENTION - obj += "virtual " - obj += TypeCoder.func_result(f) - obj += " _method_" - obj += f.ident - obj += self.params(f.params) - obj += " {" - if !f.is_void() { - obj += " return {}; " + fn prepare_structure(mut self, mut &s: &Struct) { + for (_, mut ins) in s.instances { + for (_, mut m) in ins.methods { + if m.statically { + continue + } + for (_, mut ins) in m.instances { + let mut p = ins.params[0] + if !p.decl.is_ref() { + p.kind = &TypeKind{ + kind: &CustomType{ + kind: TypeCoder.as_ptr(TypeCoder.kind(p.kind)), + } + } + } else { + p.kind = &TypeKind{ + kind: &CustomType{ + kind: TypeCoder.kind(p.kind), + } + } + } + } } - obj += "}\n" } - obj += "};" - ret obj } - // Generates C++ code of SymbolTable's all traits. - fn traits_tbl(mut self, mut &tbl: &SymbolTable): str { - let mut obj = "" - for (_, mut t) in tbl.traits { - obj += self.trait_def(t) - obj += "\n\n" + fn prepare_structures(mut self) { + for (_, mut s) in self.ir.ordered.structs { + if !s.cpp_linked && s.token.id != TokenId.Na { + self.prepare_structure(s) + } } - ret obj } - // Generates C++ code of package's all traits. - fn traits_pkg(mut self, mut &pkg: &Package): str { - let mut obj = "" - for (_, mut tbl) in pkg.files { - obj += self.traits_tbl(tbl) + fn build_trait_wrapper(mut self, mut &hash: &TraitHash) { + for (_, mut m) in hash.t.methods { + let ident = m.ident + m.instances[0].scope = nil + let ptr = !m.params[0].is_ref() + + let mut sm = hash.s.find_method(m.ident, false) + if sm == nil || sm.instances.len == 0 { + continue + } + + m.ident = ident + "_" + conv::itoa(hash.i) + self.trait_wrappers += self.func(m) + m.ident = ident + self.add_indent() + self.trait_wrappers += "{\n" + self.trait_wrappers += self.indent() + if !sm.is_void() { + self.trait_wrappers += "return " + } + self.trait_wrappers += IdentCoder.func(sm) + self.trait_wrappers += "(" + if ptr { + self.trait_wrappers += "_self_.safe_ptr<" + self.trait_wrappers += TypeCoder.structure_ins(hash.s) + self.trait_wrappers += ">(" + if !env::PRODUCTION { + self.trait_wrappers += "_00___file" + } + self.trait_wrappers += ")" + } else { + self.trait_wrappers += "_self_.data.as<" + self.trait_wrappers += TypeCoder.structure(sm.owner) + self.trait_wrappers += ">()" + } + for _, mp in m.params[1:] { + self.trait_wrappers += ", " + self.trait_wrappers += IdentCoder.param(mp) + } + self.trait_wrappers += ");\n}\n" + self.done_indent() } - ret obj } - // Generates C++ code of all traits. - fn traits(mut self): str { - let mut obj = "" - for (_, mut u) in self.ir.used { - if !u.cpp_linked { - obj += self.traits_pkg(u.package) + fn trait_decl(mut self, mut &t: &Trait) { + let ident = IdentCoder.trait_decl(t) + + let type_data = ident + "MptrData" + self.trait_data_t += "struct " + self.trait_data_t += type_data + self.trait_data_t += " {\n" + + for (_, mut m) in t.methods { + let mut ins = m.instances[0] + let mut p = ins.params[0] + p.kind = &TypeKind{ + kind: t, + } + for (i, mut ip) in ins.params[1:] { + if is_anon_ident(ip.decl.ident) { + ip.decl.ident = "_" + conv::itoa(i) + } + } + if !env::PRODUCTION { + ins.params = append(ins.params, &ParamIns{ + decl: &Param{ + ident: "__file", + }, + kind: &TypeKind{ + kind: &CustomType{ + kind: "const char*", + }, + } + }) } + + self.add_indent() + self.trait_data_t += self.func_decl(m, true) + self.done_indent() } - obj += self.traits_pkg(self.ir.main) - ret obj - } + self.trait_data_t += self.indent() + self.trait_data_t += "};" + self.trait_data_t += "\n\n" + + let n = self.trait_map.len + let mut i = 0 + for (_, mut s) in t.implemented { + for (_, mut ins) in s.instances { + let mut hash = &TraitHash{ + t: t, + s: ins, + i: i, + } + i++ + self.build_trait_wrapper(hash) + self.trait_map = append(self.trait_map, hash) + } + } + self.trait_declarations += "struct " + self.trait_declarations += ident + self.trait_declarations += " {};\n" - // Generates C++ declaration code of trait. - fn trait_decl(mut self, &t: &Trait): str { - let mut obj = "struct " - obj += IdentCoder.trait_decl(t) - obj += ";" - ret obj + self.add_indent() + + self.trait_data += "static " + self.trait_data += type_data + self.trait_data += " " + self.trait_data += ident + self.trait_data += "_mptr_data[] = {\n" + + for (_, mut hash) in self.trait_map[n:] { + self.trait_data += self.indent() + self.trait_data += "{\n" + self.add_indent() + for (_, mut m) in hash.t.methods { + let m_ident = IdentCoder.func(m) + self.trait_data += self.indent() + self.trait_data += "." + self.trait_data += m_ident + self.trait_data += "=" + self.trait_data += m_ident + self.trait_data += "_" + self.trait_data += conv::itoa(hash.i) + self.trait_data += ",\n" + } + self.done_indent() + self.trait_data += self.indent() + self.trait_data += "},\n" + } + + self.done_indent() + self.trait_data += self.indent() + self.trait_data += "};" } - // Generates C++ declaration code of all traits. - fn trait_decls(mut self, mut &p: &Package): str { - let mut obj = "" + fn trait_decls(mut self, mut &p: &Package) { for (_, mut f) in p.files { - for _, t in f.traits { + for (_, mut t) in f.traits { if t.token.id != TokenId.Na { - obj += self.trait_decl(t) - obj += "\n" + self.trait_decl(t) } } } - ret obj } // Generates C++ plain-prototype code of structure. @@ -319,21 +443,6 @@ impl ObjectCoder { ret obj } - // Generates C++ derive code of structure's implemented traits. - fn structure_traits(mut self, &s: &Struct): str { - if s.implements.len == 0 { - ret "" - } - let mut obj = ": " - for _, i in s.implements { - obj += "public " - obj += IdentCoder.trait_decl(i) - obj += "," - } - obj = obj[:obj.len-1] // Remove last comma. - ret obj - } - // Generats C++ code of variable with initialize expression. fn var_init_expr(mut self, mut &v: &Var, init: str): str { let mut obj = "" @@ -386,24 +495,6 @@ impl ObjectCoder { ret obj } - fn build_structure_self_field_kind(mut self, mut &s: &StructIns): str { - ret TypeCoder.as_sptr(TypeCoder.structure_ins(s)) - } - - // Generates C++ field declaration code of structure's self field. - fn structure_self_field(mut self, mut &s: &StructIns): str { - let mut obj = self.build_structure_self_field_kind(s) - obj += " self;" - ret obj - } - - fn structure_self_field_init_st(mut self, mut &s: &StructIns): str { - let mut obj = "this->self = " - obj += self.build_structure_self_field_kind(s) - obj += "::make(this, nullptr);" - ret obj - } - fn structure_constructor(mut self, mut &s: &StructIns): str { let mut obj = IdentCoder.structure_ins(s) @@ -433,18 +524,7 @@ impl ObjectCoder { obj = obj[:obj.len-2] // Remove trailing comma. } - obj += " {" - if s.decl.has_ref_accessible() { - obj += "\n" - self.add_indent() - obj += self.indent() - obj += self.structure_self_field_init_st(s) - obj += "\n" - self.done_indent() - obj += "\n" - obj += self.indent() - } - obj += "}" + obj += " {}" ret obj } @@ -452,27 +532,15 @@ impl ObjectCoder { const STATIC = false // Dispose method must be non-static let dispose_method = s.find_method("dispose", STATIC) let mut disposed = FuncPattern.dispose(dispose_method) - let ref_access = s.decl.has_ref_accessible() // Call destructor if implemented. - if !ref_access && !disposed { + if !disposed { ret "" } - let mut obj = "~" obj += IdentCoder.structure_ins(s) obj += "(void) { " - - if disposed { - obj += "this->" - obj += IdentCoder.func(dispose_method) - obj += "(); " - } - - if ref_access { - obj += "this->self.ref = nullptr; " - } - - obj += "}" + obj += IdentCoder.func(dispose_method) + obj += "(this); }" ret obj } @@ -577,16 +645,15 @@ impl ObjectCoder { if !assignment { obj += "return " } - obj += "this->" obj += IdentCoder.func_ins(f) if !unary { - obj += "(_other); " + obj += "(this, _other); " if assignment { obj += "return *this; " } obj += "}" } else { - obj += "(); }" + obj += "(this); }" } obj += "\n\n" } @@ -643,21 +710,22 @@ impl ObjectCoder { } fn structure_ins_decl(mut self, mut &s: &StructIns): str { - let mut obj = "struct " + let mut obj = "" + + if s.methods.len > 0 { + for (_, mut m) in s.methods { + obj += self.func_decl(m, false) + } + } + + obj += "struct " let out_ident = IdentCoder.structure_ins(s) obj += out_ident - obj += self.structure_traits(s.decl) obj += " {\n" - let ref_access = s.decl.has_ref_accessible() self.add_indent() - if ref_access { - obj += self.indent() - obj += self.structure_self_field(s) - obj += "\n\n" - } if s.fields.len > 0 { for (_, mut f) in s.fields { obj += self.indent() @@ -677,18 +745,7 @@ impl ObjectCoder { // Default constructor. obj += self.indent() obj += out_ident - if ref_access { - obj += "(void) { " - obj += self.structure_self_field_init_st(s) - obj += " }\n\n" - } else { - obj += "(void) = default;\n\n" - } - - for (_, mut f) in s.methods { - obj += self.func_decl(f, true) - obj += "\n\n" - } + obj += "(void) = default;\n\n" obj += self.structure_derive_defs_decls(s) @@ -697,6 +754,7 @@ impl ObjectCoder { self.done_indent() obj += self.indent() + "};" + ret obj } @@ -705,7 +763,6 @@ impl ObjectCoder { let mut obj = "" for (_, mut ins) in s.instances { obj += self.structure_ins_decl(ins) - obj += "\n\n" } ret obj } @@ -722,33 +779,29 @@ impl ObjectCoder { ret obj } - fn func_head(mut self, mut &f: &FnIns, method: bool): str { + fn func_head(mut self, mut &f: &FnIns, ptr: bool): str { let mut obj = "" - - if method && f.decl.statically { - obj += "static " - } - - if env::OPT_INLINE && !f.decl.is_entry_point() { + if !ptr && env::OPT_INLINE && !f.decl.is_entry_point() { obj += "inline " } - obj += TypeCoder.func_ins_result(f) - obj += " " - if !method && f.decl.owner != nil { - obj += IdentCoder.structure_ins(f.owner) - obj += "::" + if ptr { + obj += "(*" + obj += IdentCoder.func_ins(f) + obj += ")" + } else { + obj += " " + obj += IdentCoder.func_ins(f) } - obj += IdentCoder.func_ins(f) ret obj } // Generates C++ declaration code of function's combinations. - fn func_decl(mut self, mut &f: &Fn, method: bool): str { + fn func_decl(mut self, mut &f: &Fn, ptr: bool): str { let mut obj = "" for (_, mut c) in f.instances { obj += self.indent() - obj += self.func_head(c, method) + obj += self.func_head(c, ptr) obj += self.params_decls(c.params) obj += ";\n" } @@ -768,22 +821,25 @@ impl ObjectCoder { ret obj } - // Generates C++ code of all can-be-prototyped declarations. - fn decls(mut self): str { - let mut obj = "" - + fn build_trait_map(mut self) { for (_, mut u) in self.ir.used { if !u.cpp_linked { - obj += self.trait_decls(u.package) + self.trait_decls(u.package) } } - obj += self.trait_decls(self.ir.main) + self.trait_decls(self.ir.main) + } + fn process_traits(mut self) { + self.build_trait_map() + } - obj += self.structure_plain_decls() + // Generates C++ code of all can-be-prototyped declarations. + fn decls(mut self): str { + let mut obj = "" - obj += self.traits() - obj += "\n" + obj += self.trait_declarations + obj += self.structure_plain_decls() obj += self.structure_decls() @@ -794,6 +850,15 @@ impl ObjectCoder { } obj += self.func_decls(self.ir.main) + if self.trait_map.len > 0 { + obj += "\n\n" + obj += self.trait_data_t + obj += "\n\n" + obj += self.trait_wrappers + obj += "\n\n" + obj += self.trait_data + } + ret obj } @@ -850,7 +915,9 @@ impl ObjectCoder { obj += self.params_ins(ins.params) obj += " " obj += self.sc.func_scope(ins) - obj += "\n\n" + if ins.scope != nil { + obj += "\n\n" + } } ret obj } @@ -887,19 +954,17 @@ impl ObjectCoder { fn structure_ostream(mut self, mut &s: &StructIns): str { let mut obj = "" obj += self.indent() - obj += "std::ostream &operator<<(std::ostream &_Stream, const " + obj += "std::ostream &operator<<(std::ostream &_Stream, " obj += IdentCoder.structure_ins(s) - obj += " &_Src) {\n" + obj += " _Src) {\n" self.add_indent() obj += self.indent() let mut fts = s.find_method("to_str", false) if FuncPattern.to_str(fts) { - obj += "_Stream << ((" - obj += IdentCoder.structure_ins(s) - obj += ")(_Src))." + obj += "_Stream << " obj += IdentCoder.func(fts) - obj += "();\n" + obj += "(&_Src);\n" } else { obj += `_Stream << "` obj += s.decl.ident @@ -1111,6 +1176,8 @@ int main(int argc, char *argv[], char *envp[]) { // Returns fully implemented IR in C++. // Except standard content, to add standard content, use [ObjectCoder.append_standard]. pub fn serialize(mut self): str { + self.prepare_structures() + self.process_traits() let mut global_initializers = "" let mut obj = "" obj += self.links() diff --git a/src/julec/obj/cxx/scope.jule b/src/julec/obj/cxx/scope.jule index 9727ba28c..2572c94f5 100644 --- a/src/julec/obj/cxx/scope.jule +++ b/src/julec/obj/cxx/scope.jule @@ -735,6 +735,9 @@ impl ScopeCoder { // Generates C++ code of function's scope. fn func_scope(mut self, mut f: &FnIns): str { + if f.scope == nil { + ret "" + } let mut obj = self.scope(f.scope) if f.decl.exceptional && f.decl.is_void() { // Just for void exceptionals. diff --git a/src/julec/obj/cxx/type.jule b/src/julec/obj/cxx/type.jule index dc2c017f7..a006ede14 100644 --- a/src/julec/obj/cxx/type.jule +++ b/src/julec/obj/cxx/type.jule @@ -22,6 +22,7 @@ use std::jule::sema::{ ParamIns, Fn, Param, + Kind, } use types for std::jule::types @@ -40,18 +41,33 @@ fn has_directive(&directives: []&ast::Directive, tag: str): bool { ret find_directive(unsafe { *(&directives) }, tag) != nil } +struct CustomType { + kind: str +} + +impl Kind for CustomType { + pub fn to_str(self): str { + ret self.kind + } + + pub fn equals(&self, k: &TypeKind): bool { + ret false + } +} + struct TypeCoder {} impl TypeCoder { - const Str = "jule::Str" - const Map = "jule::Map" - const Ptr = "jule::Ptr" - const Sptr = "jule::Sptr" - const Slice = "jule::Slice" - const Trait = "jule::Trait" - const Array = "jule::Array" - const Fn = "jule::Fn" - const Bool = "jule::Bool" + const Str = "jule::Str" + const Map = "jule::Map" + const Ptr = "jule::Ptr" + const Sptr = "jule::Sptr" + const Slice = "jule::Slice" + const Trait = "jule::Trait2" + const Array = "jule::Array" + const Fn = "jule::Fn" + const Bool = "jule::Bool" + const Uintptr = "jule::Uintptr" // Returns given identifier as Jule type identifier. static fn to_type(mut id: str): str { @@ -87,6 +103,11 @@ impl TypeCoder { ret obj } + // Returns C++ code of pointer type with element type. + static fn as_ptr(elem: str): str { + ret elem + "*" + } + // Generates C++ code of smart pointer TypeKind. static fn sptr(mut sptr: &Sptr): str { ret TypeCoder.as_sptr(TypeCoder.kind(sptr.elem)) @@ -194,6 +215,9 @@ impl TypeCoder { } else { obj += TypeCoder.kind(p.kind.kind) } + if p.reference { + obj += "&" + } ret obj } @@ -295,6 +319,10 @@ impl TypeCoder { ret TypeCoder.array(k.arr()) | k.fnc() != nil: ret TypeCoder.func(k.fnc()) + } + match type k.kind { + | &CustomType: + ret (&CustomType)(k.kind).kind |: ret "[]" } diff --git a/src/julec/optimizing/expr.jule b/src/julec/optimizing/expr.jule index 9d64b0d49..155fb9ac3 100644 --- a/src/julec/optimizing/expr.jule +++ b/src/julec/optimizing/expr.jule @@ -93,8 +93,9 @@ impl ExprOptimizer { match m.op.kind { | TokenKind.Eqs: *self.model = &CommonSubIdentExprModel{ - expr: m.left.model, - ident: "empty()", + expr_kind: m.left.kind, + expr: m.left.model, + ident: "empty()", } | TokenKind.NotEq: let mut op = m.op @@ -103,8 +104,9 @@ impl ExprOptimizer { op: op, expr: &Data{ model: &CommonSubIdentExprModel{ - expr: m.left.model, - ident: "empty()", + expr_kind: m.left.kind, + expr: m.left.model, + ident: "empty()", }, }, } @@ -277,7 +279,7 @@ impl ExprOptimizer { } fn structure_sub(self, mut m: &StructSubIdentExprModel) { - ExprOptimizer.optimize(m.expr) + ExprOptimizer.optimize(m.expr.model) } fn common_sub(self, mut m: &CommonSubIdentExprModel) { diff --git a/std/flag/flag.jule b/std/flag/flag.jule index 8ebcb2a18..2efbe9a20 100644 --- a/std/flag/flag.jule +++ b/std/flag/flag.jule @@ -128,7 +128,7 @@ impl FlagSet { match type T { | i64 | u64 | f64 | bool | str: // Ok - + break |: panic("std::flag: FlagSet.add[T]: unsupported typed for flag") } diff --git a/std/jule/sema/eval.jule b/std/jule/sema/eval.jule index 74406698c..895d96423 100644 --- a/std/jule/sema/eval.jule +++ b/std/jule/sema/eval.jule @@ -2030,16 +2030,19 @@ impl Eval { lvalue: false, decl: false, mutable: false, - kind: &TypeKind{kind: f.instance()}, + kind: &TypeKind{ + kind: f.instance(), + }, model: &TraitSubIdentExprModel{ - token: ident, - expr: d.model, - ident: ident.kind, + token: ident, + expr: d.model, + method: f, + trt: trt, }, } } - fn eval_struct_sub_ident(mut self, mut d: &Data, mut s: &StructIns, si: &SubIdentExpr, ref: bool): &Data { + fn eval_struct_sub_ident(mut self, mut d: &Data, mut s: &StructIns, mut si: &SubIdentExpr, ref: bool): &Data { let mut f = s.find_field(si.ident.kind) if f != nil { if !self.s.is_accessible_define(f.decl.public, f.decl.token) { @@ -2048,8 +2051,9 @@ impl Eval { } let mut model = &StructSubIdentExprModel{ + token: si.ident, expr_kind: d.kind, - expr: d.model, + expr: new(Data, *d), field: f, } d.model = model @@ -2088,22 +2092,25 @@ impl Eval { let mut ins = m.instance() ins.owner = s self.push_reference_to_fn(ins) + let mut model = new(Data, *d) d.model = &StructSubIdentExprModel{ + token: si.ident, expr_kind: d.kind, - expr: d.model, + expr: model, method: ins, } d.kind = &TypeKind{kind: ins} ret d } - fn eval_slice_sub_ident(mut self, mut d: &Data, ident: Token): &Data { + fn eval_slice_sub_ident(mut self, mut d: &Data, mut ident: Token): &Data { match ident.kind { | "len": ret &Data{ mutable: false, kind: &TypeKind{kind: build_prim_type(PrimKind.Int)}, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "len()", @@ -2114,6 +2121,7 @@ impl Eval { mutable: false, kind: &TypeKind{kind: build_prim_type(PrimKind.Int)}, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "cap()", @@ -2142,6 +2150,7 @@ impl Eval { }, }, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "swap", @@ -2154,7 +2163,7 @@ impl Eval { } } - fn eval_array_sub_ident(mut self, mut d: &Data, ident: Token): &Data { + fn eval_array_sub_ident(mut self, mut d: &Data, mut ident: Token): &Data { match ident.kind { | "len": let mut c = Const.new_i64(i64(d.kind.arr().n)) @@ -2187,6 +2196,7 @@ impl Eval { }, }, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "swap", @@ -2199,7 +2209,7 @@ impl Eval { } } - fn eval_map_sub_ident(mut self, mut d: &Data, ident: Token): &Data { + fn eval_map_sub_ident(mut self, mut d: &Data, mut ident: Token): &Data { let mut map_kind = d.kind.map() match ident.kind { @@ -2208,6 +2218,7 @@ impl Eval { mutable: false, kind: &TypeKind{kind: build_prim_type(PrimKind.Int)}, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "len()", @@ -2222,6 +2233,7 @@ impl Eval { }, }, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "clear", @@ -2241,6 +2253,7 @@ impl Eval { }, }, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "keys", @@ -2260,6 +2273,7 @@ impl Eval { }, }, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "values", @@ -2283,6 +2297,7 @@ impl Eval { }, }, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "has", @@ -2305,6 +2320,7 @@ impl Eval { }, }, model: &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "del", @@ -2316,7 +2332,7 @@ impl Eval { } } - fn eval_str_sub_ident(mut self, mut d: &Data, ident: Token): &Data { + fn eval_str_sub_ident(mut self, mut d: &Data, mut ident: Token): &Data { let mut str_kind = &TypeKind{kind: build_prim_type(PrimKind.Str)} match ident.kind { | "len": @@ -2328,6 +2344,7 @@ impl Eval { sd.model = sd.constant } else { sd.model = &CommonSubIdentExprModel{ + token: ident, expr_kind: d.kind, expr: d.model, ident: "len()", @@ -2679,36 +2696,18 @@ impl Eval { } let mut kind = d.kind - if d.kind.ptr() != nil { + match { + | d.kind.ptr() != nil: let ptr = d.kind.ptr() - if !ptr.is_unsafe() { - if !si.is_self && !self.is_unsafe() { - self.push_err(si.ident, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) - } - kind = d.kind.ptr().elem - let mut model = new(Data, *d) - - // Append dereferencing model for pointer. - let mut token = si.ident - token.id = TokenId.Op - token.kind = TokenKind.Star - d.model = &UnaryExprModel{ - expr: model, - op: token, - } + if ptr.is_unsafe() { + break } - } else if d.kind.sptr() != nil { - kind = d.kind.sptr().elem - - // Append dereferencing model for pointer. - let mut model = new(Data, *d) - let mut token = si.ident - token.id = TokenId.Op - token.kind = TokenKind.Star - d.model = &UnaryExprModel{ - expr: model, - op: token, + if !si.is_self && !self.is_unsafe() { + self.push_err(si.ident, LogMsg.UnsafeBehaviorAtOutOfUnsafeScope) } + kind = d.kind.ptr().elem + | d.kind.sptr() != nil: + kind = d.kind.sptr().elem } match { diff --git a/std/jule/sema/model.jule b/std/jule/sema/model.jule index 0bb318be3..b6e920acc 100644 --- a/std/jule/sema/model.jule +++ b/std/jule/sema/model.jule @@ -117,15 +117,17 @@ pub struct SlicingExprModel { // Trait sub-ident expression model. // For example: my_trait.my_sub_ident pub struct TraitSubIdentExprModel { - pub token: Token - pub expr: ExprModel - pub ident: str + pub token: Token + pub expr: ExprModel + pub method: &Fn + pub trt: &Trait } // Structure sub-ident expression model. // For example: my_struct.my_sub_ident pub struct StructSubIdentExprModel { - pub expr: ExprModel + pub token: Token + pub expr: &Data pub expr_kind: &TypeKind pub method: &FnIns pub field: &FieldIns @@ -156,6 +158,7 @@ pub struct CommonIdentExprModel { pub struct CommonSubIdentExprModel { pub expr_kind: &TypeKind pub expr: ExprModel + pub token: Token pub ident: str } diff --git a/std/jule/sema/scope.jule b/std/jule/sema/scope.jule index a83016fc4..9dd691f3b 100644 --- a/std/jule/sema/scope.jule +++ b/std/jule/sema/scope.jule @@ -1223,17 +1223,15 @@ impl ScopeChecker { ret } - self.scope.stmts = append(self.scope.stmts, &Assign{ - l: &OperandExprModel{ - kind: l.kind, - model: l.model, - }, - r: &OperandExprModel{ - kind: r.kind, - model: r.model, - }, - op: a.setter, - }) + let mut lm = &OperandExprModel{ + kind: l.kind, + model: l.model, + } + let mut rm = &OperandExprModel{ + kind: r.kind, + model: r.model, + } + self.scope.stmts = append(self.scope.stmts, &Assign{l: lm, r: rm, op: a.setter}) if a.setter.kind != TokenKind.Eq { let mut strct = l.kind.strct() @@ -1258,7 +1256,10 @@ impl ScopeChecker { d: r, error_token: a.setter, } - checker.check() + if checker.check() { + rm.model = r.model + lm.model = l.model + } } fn __process_end_part_of_multi_assign(mut self, mut st: &MultiAssign, @@ -1560,11 +1561,13 @@ impl ScopeChecker { for (_, mut c) in tm.cases { if c.scope != nil { self.check_comptime_panic(c.scope) - self.scope.stmts = append(self.scope.stmts, c.scope) - ret + tm.default = c + tm.cases = nil + goto push } } if m.default != nil { + tm.cases = nil tm.default = self.check_default(tm, m.default) if tm.default != nil { self.check_comptime_panic(tm.default.scope) @@ -1572,6 +1575,7 @@ impl ScopeChecker { } ret } + push: self.scope.stmts = append(self.scope.stmts, tm) } diff --git a/std/jule/sema/sema.jule b/std/jule/sema/sema.jule index 11e712cb2..6b94b9c22 100644 --- a/std/jule/sema/sema.jule +++ b/std/jule/sema/sema.jule @@ -15,7 +15,7 @@ fn is_valid_model_for_ref(mut &m: ExprModel): bool { ret true | &StructSubIdentExprModel: let mut model = (&StructSubIdentExprModel)(m) - ret is_valid_model_for_ref(model.expr) + ret is_valid_model_for_ref(model.expr.model) | &TraitSubIdentExprModel: let mut model = (&TraitSubIdentExprModel)(m) ret is_valid_model_for_ref(model.expr) @@ -528,43 +528,36 @@ impl Sema { | bool: // Pass, built-in. continue - | &Var: let mut v = (&Var)(def) if self.is_accessible_define(v.public, v.token) { continue } - | &TypeAlias: let mut ta = (&TypeAlias)(def) if self.is_accessible_define(ta.public, ta.token) { continue } - | &Struct: let mut strct = (&Struct)(def) if self.is_accessible_define(strct.public, strct.token) { continue } - | &Trait: let mut t = (&Trait)(def) if self.is_accessible_define(t.public, t.token) { continue } - | &Enum: let mut e = (&Enum)(def) if self.is_accessible_define(e.public, e.token) { continue } - | &Fn: let mut f = (&Fn)(def) if self.is_accessible_define(f.public, f.token) { continue } - |: self.push_err(ident, LogMsg.IdentNotExist, ident.kind) ok = false @@ -751,10 +744,6 @@ impl Sema { self.push_err(error_token, LogMsg.InvalidExpr) ret false } - /*if d.kind.variadic { - self.push_err(error_token, LogMsg.InvalidExpr) - ret - }*/ if dest_is_ref { if !dest.equals(d.kind) { self.push_err(error_token, LogMsg.IncompatibleTypes, dest.to_str(), d.kind.to_str()) @@ -905,7 +894,21 @@ impl Sema { ok = true for (_, mut p) in f.params { - if !p.decl.is_self() { + if p.decl.is_self() { + if p.decl.is_ref() { + p.kind = &TypeKind{ + kind: &Sptr{ + elem: &TypeKind{ + kind: f.owner, + }, + } + } + } else { + p.kind = &TypeKind{ + kind: f.owner, + } + } + } else { p.kind = sema.build_type_with_generics(p.decl.kind.decl, generics) if p.kind != nil { p.kind.variadic = p.decl.variadic @@ -938,12 +941,12 @@ impl Sema { | &TraitSubIdentExprModel: let mut model = (&TraitSubIdentExprModel)(d.model) if !is_valid_model_for_ref(model.expr) { - self.push_err(error_token, LogMsg.RefIsDangling, model.ident) + self.push_err(error_token, LogMsg.RefIsDangling, model.method.ident) ret false } | &StructSubIdentExprModel: let mut model = (&StructSubIdentExprModel)(d.model) - if !is_valid_model_for_ref(model.expr) { + if !is_valid_model_for_ref(model.expr.model) { self.push_err(error_token, LogMsg.RefIsDangling, model.field.decl.ident) ret false } @@ -1330,9 +1333,9 @@ impl Sema { } match { - | !self.check_decl_generics(f.generics): ret - | !self.check_fn_decl_params_dup(f): ret - | !self.check_fn_decl_result_dup(f): ret + | !self.check_decl_generics(f.generics): + | !self.check_fn_decl_params_dup(f): + | !self.check_fn_decl_result_dup(f): } self.check_fn_decl_types(f) @@ -1369,7 +1372,6 @@ impl Sema { | j >= i: // Skip current and following methods. break duplicate_lookup - | f.ident == jf.ident: self.push_err(f.token, LogMsg.DuplicatedIdent, f.ident) self.push_suggestion(LogMsg.RenameForAvoidDuplication) @@ -1529,8 +1531,10 @@ impl Sema { // Implement implementation. fn impl_impl(mut &self, mut &decl: &Impl) { match { - | decl.is_trait_impl(): self.impl_trait(decl) - | decl.is_struct_impl(): self.impl_struct(decl) + | decl.is_trait_impl(): + self.impl_trait(decl) + | decl.is_struct_impl(): + self.impl_struct(decl) } } @@ -2336,6 +2340,11 @@ impl Sema { // Prechecks types of current package file's functions. fn precheck_fn_types(mut &self) { + for (_, mut decl) in self.file.traits { + for (_, mut m) in decl.methods { + self.precheck_type_fn(m) + } + } for (_, mut decl) in self.file.funcs { self.precheck_type_fn(decl) } diff --git a/std/jule/sema/type.jule b/std/jule/sema/type.jule index dc4a21958..23872b83d 100644 --- a/std/jule/sema/type.jule +++ b/std/jule/sema/type.jule @@ -320,12 +320,14 @@ impl TypeSymbol { // Primitive type. pub struct Prim { - kind: str + pub kind: str } impl Kind for Prim { // Returns kind. - pub fn to_str(self): str { ret self.kind } + pub fn to_str(self): str { + ret self.kind + } // Reports whether types are same. pub fn equals(&self, other: &TypeKind): bool { @@ -1506,3 +1508,14 @@ impl TypeChecker { t.kind = kind } } + +fn apply_implicit_cast(mut &dest: &TypeKind, mut &d: &Data) { + if d.kind.is_nil() { + ret + } + if dest.trt() != nil && d.kind.trt() == nil { + d.cast_kind = dest + apply_cast_kind_model(d) + d.cast_kind = nil + } +} diff --git a/std/jule/sema/type2.jule b/std/jule/sema/type2.jule index 4a5699a63..3e8d27d22 100644 --- a/std/jule/sema/type2.jule +++ b/std/jule/sema/type2.jule @@ -297,7 +297,7 @@ impl AssignTypeChecker { ret self.dest.prim() != nil && self.d.kind.prim() != nil } - fn check(mut self): bool { + fn check_compatibility(mut self): bool { match { | self.d == nil: // Skip Data is nil. @@ -329,6 +329,14 @@ impl AssignTypeChecker { } ret self.s.check_type_compatibility(self.dest, self.d.kind, self.error_token) } + + fn check(mut self): bool { + let ok = self.check_compatibility() + if ok { + apply_implicit_cast(self.dest, self.d) + } + ret ok + } } struct DynamicTypeAnnotation { @@ -665,8 +673,8 @@ impl FnCallArgChecker { break } - model.elems = append(model.elems, d.model) ok = ok && self.check_arg(p, d, arg.token) + model.elems = append(model.elems, d.model) } self.e.prefix = old @@ -757,16 +765,16 @@ impl StructLitChecker { } fn push_match(mut self, mut &f: &FieldIns, mut &d: &Data, mut &error_token: Token) { - self.args = append(self.args, &StructArgExprModel{ - field: f, - expr: d.model, - }) const REFERENCE = false if self.e.s.check_validity_for_init_expr(!self.e.immutable, REFERENCE, f.kind, d, error_token) { // Check type if validity is good. // Helps to reduce error logs and duplicated logs. _ = self.e.s.check_assign_type(false, f.kind, d, error_token) } + self.args = append(self.args, &StructArgExprModel{ + field: f, + expr: d.model, + }) } fn check_pair(mut self, mut &pair: &FieldExprPair, mut &exprs: []&Expr) {