diff --git a/src/julec/obj/cxx/expr.jule b/src/julec/obj/cxx/expr.jule index b47b86512..a38c8319e 100644 --- a/src/julec/obj/cxx/expr.jule +++ b/src/julec/obj/cxx/expr.jule @@ -263,10 +263,12 @@ impl exprCoder { ret } + // Special cases for comparable types. if op == TokenId.Eqs || op == TokenId.NotEq { - // If this binary operator comparing type. - // The m.Left is will be one always. - if obj::IsAny(lk) { + match { + | obj::IsAny(lk): + // If this binary operator comparing type. + // The left operand is will be one always. if !rk.IsNil() && !obj::IsAny(rk) { buf.WriteByte('(') if op == TokenId.NotEq { @@ -282,6 +284,24 @@ impl exprCoder { buf.WriteStr("))") ret } + | lk.Arr() != nil: + // If this binary operator comparing array type. + // The left operand is will be array one always. + arr := lk.Arr() + mut f := obj::RuntimeFindFn(self.oc.ir.Runtime, obj::RuntimeFunc.arrayCmp) + mut ins := obj::FindGenericInstance(f, arr.Elem) + identCoder.funcIns(buf, ins) + if op == TokenId.NotEq { + buf.WriteByte('!') + } + buf.WriteByte('(') + buf.WriteStr(l) + buf.WriteStr(".begin(), ") + buf.WriteStr(r) + buf.WriteStr(".begin(), ") + buf.WriteStr(conv::Itoa(arr.N)) + buf.WriteByte(')') + ret } } buf.WriteByte('(') diff --git a/src/julec/obj/cxx/object.jule b/src/julec/obj/cxx/object.jule index 90836eaf3..d9dcb16a5 100644 --- a/src/julec/obj/cxx/object.jule +++ b/src/julec/obj/cxx/object.jule @@ -566,7 +566,7 @@ impl ObjectCoder { self.write("(this); }") } - fn structureOperatorEq(mut &self, ident: str, mut &s: &StructIns) { + fn structureOperatorEq(mut &self, ident: str, mut &s: &StructIns, decl: bool) { if !defaultEq(s) { ret } @@ -581,7 +581,13 @@ impl ObjectCoder { self.write(ident) self.write(" *_self_, ") self.write(ident) - self.write(" _other_) {") + self.write(" _other_)") + if decl { + // Declaration only. + self.write(";\n\n") + ret + } + self.write(" {") if len(s.Fields) == 0 { self.write(" return true; }\n\n") ret @@ -628,13 +634,13 @@ impl ObjectCoder { self.write("}\n\n") } - fn structureOperators(mut &self, mut &s: &StructIns) { + fn structureOperators(mut &self, mut &s: &StructIns, decl: bool) { mut sb := StrBuilder.New(40) identCoder.structureIns(sb, s) ident := sb.Str() // Binary. - self.structureOperatorEq(ident, s) + self.structureOperatorEq(ident, s, decl) } fn structureInsDecl(mut &self, mut &s: &StructIns) { @@ -663,7 +669,8 @@ impl ObjectCoder { self.indent() self.write("};") - self.structureOperators(s) + const DeclOnly = true + self.structureOperators(s, DeclOnly) } fn structureDecl(mut &self, mut &s: &Struct) { @@ -1132,6 +1139,8 @@ impl ObjectCoder { } fn structureIns(mut &self, mut &s: &StructIns) { + const DeclOnly = false + self.structureOperators(s, DeclOnly) self.structureMethods(s) self.write("\n\n") self.structureOstream(s) diff --git a/src/julec/obj/determine.jule b/src/julec/obj/determine.jule index b102bfbb1..8d19ebc3f 100644 --- a/src/julec/obj/determine.jule +++ b/src/julec/obj/determine.jule @@ -6,6 +6,7 @@ use comptime for std::comptime use path for std::fs::path use build for std::jule::build use std::jule::sema::{ + ImportInfo, Scope, Fn, Var, @@ -93,4 +94,10 @@ fn IsStdPackage(&f: str, p: str): bool { // Do not handle '/' separators of p, because it // valid path separator for all supported platforms. ret strings::HasPrefix(f, path::Join(build::PathStdlib, p)) +} + +// Reports whether imp is implicitly imported. +// See developer reference (9). +fn IsImplicitImport(imp: &ImportInfo): bool { + ret imp.Token == nil } \ No newline at end of file diff --git a/src/julec/obj/ir.jule b/src/julec/obj/ir.jule index 4e016958a..c13e43f1d 100644 --- a/src/julec/obj/ir.jule +++ b/src/julec/obj/ir.jule @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. use env +use ast for std::jule::ast use std::jule::build::{Log, LogKind} use std::jule::importer::{JuleImporter, CompileInfo, Compiler, CppStd} use sema for std::jule::sema @@ -13,6 +14,7 @@ struct IR { Root: str Passes: []str Main: &sema::Package + Runtime: &sema::ImportInfo // std::runtime Used: []&sema::ImportInfo Ordered: OrderedDefines } @@ -21,12 +23,13 @@ impl IR { // Returns compiler IR of source code. // Returned IR is lexed, parsed, and analyzed. // - // - Returns nil reference and nil logs if path has not any Jule file. - // - Returns nil reference and logs if exist any log. + // - Returns (nil, nil) logs if path has not any Jule file. + // - Returns (nil, logs) if exist any log. // - Returns IR and nil logs if everything is fine. static fn Build(path: str, flags: sema::SemaFlag): (&IR, []Log) { mut importer := JuleImporter.New(buildCompileInfo()) - mut files, mut logs := importer.ImportPackage(path, true) + const UpdateMod = true // Use root module for project if exist. + mut files, mut logs := importer.ImportPackage(path, UpdateMod) if len(logs) > 0 { ret nil, logs } @@ -36,6 +39,10 @@ impl IR { ret nil, nil } + // Push std::runtime package to first file. + // Each Jule program should import this standard package. + pushRuntimeToAST(files[0]) + mut pkg, logs := sema::AnalyzePackage(files, importer, flags) if len(logs) > 0 { ret nil, logs @@ -48,6 +55,9 @@ impl IR { } ir.Passes = getAllUniquePasses(ir.Main, ir.Used) + // Set up special packages. + ir.Runtime = pkg.Files[0].Imports[0] // std::runtime + ret ir, nil } } @@ -101,10 +111,10 @@ impl IR { // Order defines at update ordered field of instance. fn Order(mut self) { - self.Ordered.Structs = self.GetAllStructures() self.Ordered.Globals = self.GetAllGlobals() - order(self.Ordered.Structs) + self.Ordered.Structs = self.GetAllStructures() order(self.Ordered.Globals) + order(self.Ordered.Structs) } } @@ -161,4 +171,23 @@ fn buildCompileInfo(): CompileInfo { } ret info +} + +// See [std::jule] developer reference (9). +fn pushRuntimeToAST(mut &f: &ast::Ast) { + mut decl := &ast::UseDecl{ + Token: nil, // Nil token is a flag for implicit declaration. + LinkPath: "std::runtime", + Alias: "", + Full: false, + Selected: nil, + Binded: false, + Std: true, + } + if len(f.UseDecls) > 0 { + f.UseDecls = append(f.UseDecls[:1], f.UseDecls...) + f.UseDecls[0] = decl + } else { + f.UseDecls = append(f.UseDecls, decl) + } } \ No newline at end of file diff --git a/src/julec/obj/lookup.jule b/src/julec/obj/lookup.jule index 794e8a6e8..1ea899316 100644 --- a/src/julec/obj/lookup.jule +++ b/src/julec/obj/lookup.jule @@ -5,7 +5,7 @@ use comptime for std::comptime use ast for std::jule::ast use std::jule::lex::{TokenId} -use std::jule::sema::{Trait, StructIns, TypeKind, FnIns} +use std::jule::sema::{Trait, StructIns, TypeKind, Fn, FnIns} // Returns directive if exist. fn FindDirective(mut &directives: []&ast::Directive, tag: str): &ast::Directive { @@ -139,4 +139,20 @@ fn FindOperator(mut &s: &StructIns, op: TokenId, unary: bool): &FnIns { |: ret nil } +} + +// Returns function instance by generics. +// Assumes generics parameter have enough and same size with generic count of f. +// Panics if not exist any instance. +fn FindGenericInstance(mut &f: &Fn, generics: ...&TypeKind): &FnIns { +lookup: + for (_, mut ins) in f.Instances { + for i in ins.Generics { + if !ins.Generics[i].Kind.Equal(generics[i]) { + continue lookup + } + } + ret ins + } + panic("generic instance lookup failed, this is an implementation mistake") } \ No newline at end of file diff --git a/src/julec/obj/order.jule b/src/julec/obj/order.jule index ca14cb9ce..ec971590e 100644 --- a/src/julec/obj/order.jule +++ b/src/julec/obj/order.jule @@ -34,7 +34,7 @@ lookup: ret true } -fn order[T](mut &s: []&T) { +fn order[T](mut s: []&T) { mut i := 0 repeat: mut j := i diff --git a/src/julec/obj/runtime.jule b/src/julec/obj/runtime.jule new file mode 100644 index 000000000..4bc729bfb --- /dev/null +++ b/src/julec/obj/runtime.jule @@ -0,0 +1,19 @@ +// Copyright 2024 The Jule Programming Language. +// Use of this source code is governed by a BSD 3-Clause +// license that can be found in the LICENSE file. + +use std::jule::sema::{ImportInfo, Fn} + +enum RuntimeFunc: str { + arrayCmp: "arrayCmp", +} + +fn RuntimeFindFn(mut &runtime: &ImportInfo, ident: RuntimeFunc): &Fn { + const Binded = false + mut f := runtime.FindFn(ident, Binded) + if f == nil { + outln(ident) + panic("runtime function is not exist, this is an implementation mistake, this panic call should be unreachable") + } + ret f +} \ No newline at end of file diff --git a/src/julec/opt/deadcode/define.jule b/src/julec/opt/deadcode/define.jule index 41e270fbb..0bdc4ae62 100644 --- a/src/julec/opt/deadcode/define.jule +++ b/src/julec/opt/deadcode/define.jule @@ -289,7 +289,8 @@ impl ObjectDeadCode { fn removeDeads(mut &self) { for (_, mut used) in self.ir.Used { - if !used.Binded { + // Skip binded and implicit imports. + if !used.Binded && !obj::IsImplicitImport(used) { self.removeDeadsPackage(used.Package) } } diff --git a/std/jule/README.md b/std/jule/README.md index c4043e2f2..4c2799f19 100644 --- a/std/jule/README.md +++ b/std/jule/README.md @@ -9,7 +9,7 @@ It is also used by the official reference compiler JuleC and is developed in par - [`lex`](./lex): Lexical analyzer. - [`importer`](./importer): Default Jule importer. - [`parser`](./parser): Parser. -- [`sema`](./sema): Semantic analyzer. +- [`sema`](./sema): Semantic analyzer and CAST (Compilation Abstract Syntax Tree) components. - [`types`](./types): Elementary package for type safety. ## Developer Reference @@ -49,4 +49,26 @@ For example: - **(8)** Check `enum` declarations first before using them or any using possibility appears. Enum fields should be evaluated before evaluate algorithms executed. Otherwise, probably program will panic because of unevaluated enum field(s) when tried to use. - - **(8.1)** This is not apply for type enums. Type enum's fields are type alias actually. They are should anaylsis like type aliases. \ No newline at end of file + - **(8.1)** This is not apply for type enums. Type enum's fields are type alias actually. They are should anaylsis like type aliases. + +- **(9)** Semantic analysis supports built-in use declarations for developers, but this functionality is not for common purposes. These declarations do not cause problems in duplication analysis. For example, you added the `x` package as embedded in the AST, but the source also contains a use declaration for this package, in which case a conflict does not occur.\ +\ +These packages are specially processed and treated differently than standard use declarations. These treatments only apply to supported packages. To see relevant treatments, see implicit imports section of the reference.\ +\ +Typical uses are things like capturing or tracing private behavior. For example, the reference Jule compiler may embed the `std::runtime` package for some special calls. The semantic analyzer makes the necessary private calls for this embedded package when necessary. For example, appends instance to array compare generic method for array comparions. + - **(9.1)** The `Token` field is used to distinguish specific packages. If the `Token` field of the AST element is set to `nil`, the package built-in use declaration is considered. Accordingly, AST must always set the `Token` field for each use declaration. + - **(9.2)** Semantic ananlyzer must to guarantee any duplication will not appended to imports. So, built-in implicit imported packages cannot be duplicated even placed source file contains separate use declaration for the same package. + - **(9.3)** These packages should be placed as first use declarations of the main package's first file. + - **(9.4)** Semantic analyzer will not collect references for these packages. So any definition will not have a collection of references. + - **(9.5)** If semantic anlayzer encourter same package with any implicitly imported package in the same source file, assigns token of source file declaration to implicitly imported package. It also helps to caught dupliations for same packages after first one in the source file. + +### Implicit Imports + +Implicit imports are as described in developer reference (9). This section addresses which package is supported and what special behaviors it has. + +#### `std::runtime` + +This package is a basic package developed for Jule programs and focuses on runtime functionalities. + +Here is the list of custom behaviors for this package; +- (1) `arrayCmp`: Developed to eliminate the need for the Jule compiler to generate code specifically for array comparisons for each backend and to reduce analysis cost. The semantic analyzer creates the necessary instance for this generic function when an array comparison is made. Thus, the necessary comparison function for each array is programmed at the Jule frontent level. \ No newline at end of file diff --git a/std/jule/importer/importer.jule b/std/jule/importer/importer.jule index e4f6de295..c47e2d569 100644 --- a/std/jule/importer/importer.jule +++ b/std/jule/importer/importer.jule @@ -93,12 +93,12 @@ impl Importer for JuleImporter { ret nil } - fn ImportPackage(mut self, path: str, update_mod: bool): ([]&Ast, []Log) { + fn ImportPackage(mut self, path: str, updateMod: bool): ([]&Ast, []Log) { mut dirents := Directory.Read(path) else { ret nil, [flatCompilerErr("connot read package directory: " + path)] } - if update_mod { + if updateMod { newMod := mod::FindModuleFileDeep(path) if newMod != self.mod { self.mod = newMod diff --git a/std/jule/parser/parser.jule b/std/jule/parser/parser.jule index c3752de46..b1790e3e8 100644 --- a/std/jule/parser/parser.jule +++ b/std/jule/parser/parser.jule @@ -1068,7 +1068,7 @@ impl parser { fn buildUseDecl(mut self, mut tokens: []&Token, binded: bool): &UseDecl { mut decl := &UseDecl{ - Token: tokens[0], + Token: tokens[0], // See developer reference (9). Binded: binded, } if len(tokens) < 2 { diff --git a/std/jule/sema/analysis.jule b/std/jule/sema/analysis.jule index 001c338bc..d03b60e9f 100644 --- a/std/jule/sema/analysis.jule +++ b/std/jule/sema/analysis.jule @@ -27,6 +27,21 @@ fn buildSymbols(mut &ast: &Ast, mut &importer: Importer, mut owner: &symbolBuild ret nil, sb.errors } +// See developer reference (9). +fn collectImplicitImports(mut &s: &Sema, mut &file: &SymbolTable) { + for (_, mut imp) in file.Imports { + if !isImplicitImport(imp) { + break + } + match imp.LinkPath { + | "std::runtime": + s.meta.runtime = imp + |: + panic("implementation mistake in implicit import collection, this panic call should be unreachable") + } + } +} + fn analyzePackage(mut &files: []&Ast, mut &importer: Importer, &flags: SemaFlag): (&Package, []Log) { // Build symbol tables of files. mut tables := make([]&SymbolTable, 0, len(files)) @@ -42,6 +57,11 @@ fn analyzePackage(mut &files: []&Ast, mut &importer: Importer, &flags: SemaFlag) flags: flags, meta: new(commonSemaMeta), } + + // Use first table (so first file) for this. + // See developer reference (9). + collectImplicitImports(sema, tables[0]) + sema.check(tables) if len(sema.errors) > 0 { ret nil, sema.errors diff --git a/std/jule/sema/eval.jule b/std/jule/sema/eval.jule index 77c2c880b..225ce75bd 100644 --- a/std/jule/sema/eval.jule +++ b/std/jule/sema/eval.jule @@ -1172,33 +1172,20 @@ impl Eval { // Checks new generics function instance. // If instance is already exist, f will point to exist instantantiation. - fn checkGenericFn(mut &self, mut &f: &FnIns, mut &et: &Token, mut &model: ExprModel): bool { - ok := self.s.reloadFnInsTypes(f) - f.reloaded = true - if !ok { - ret false - } - mut existInstance := f.Decl.appendInstance(f) - // TODO: [check] is possible to optimize here using same environment with realoadFnInsTypes? - if !self.s.checkConstraintsFn(f, et, existInstance) { - ret false - } - if existInstance != nil { - // Update model and references by exist function instance. + fn checkGenericFn(mut &self, mut &f: &FnIns, mut &et: &Token, mut &model: ExprModel): (ok: bool, exist: bool) { + mut old := f + ok, exist = self.s.checkGenericFn(f, et) + if ok && exist { + // Update model by exist function instance. // Generic functions returns always new instance, because might be // generics are inferred. Therefore, always returns new instance for requests. // So, if this absolute instance is already exist, update model. // Otherwise, model's instance will be a dangling, because it never // be appended into instances of function declaration since already exist. - updateModelToGenericIns(model, existInstance) - updateRefer(self.getOwnerRefers(), f, existInstance) - // Set f to exist one. - f = existInstance - } else { - // Check generic function instance instantly. - self.s.checkFnInsCaller(f, et) + updateModelToGenericIns(model, f) + updateRefer(self.getOwnerRefers(), old, f) } - ret true + ret } fn evalFnGenericFromIndexing(mut &self, mut &d: &Data, mut &i: &IndexingExpr) { @@ -1233,7 +1220,8 @@ impl Eval { ret } - if self.checkGenericFn(f, i.Expr.Token, d.Model) { + ok, _ := self.checkGenericFn(f, i.Expr.Token, d.Model) + if ok { d.Kind.Kind = f } else { d = nil @@ -2121,7 +2109,8 @@ impl Eval { d = nil ret } - if !self.checkGenericFn(f, fc.Token, d.Model) { + ok, _ = self.checkGenericFn(f, fc.Token, d.Model) + if !ok { d = nil ret } @@ -3638,6 +3627,15 @@ impl binaryEval { match self.op.Id { | TokenId.Eqs | TokenId.NotEq: + if self.e.s.meta.runtime != nil { + // Add instance to relevant runtime function for array element type if not exist. + mut f := runtimeFindFn(self.e.s.meta.runtime, runtimeFunc.arrayCmp).instanceForce() + f.Generics = append(f.Generics, &InsGeneric{Kind: self.l.Kind.Arr().Elem}) + ok, _ := self.e.s.checkGenericFn(f, self.op) + if !ok { + panic("arrayCmp evaluation failed, this is an implementation mistake") + } + } ret &Data{ Kind: primBool, } diff --git a/std/jule/sema/runtime.jule b/std/jule/sema/runtime.jule new file mode 100644 index 000000000..21f7cae86 --- /dev/null +++ b/std/jule/sema/runtime.jule @@ -0,0 +1,16 @@ +// Copyright 2024 The Jule Programming Language. +// Use of this source code is governed by a BSD 3-Clause +// license that can be found in the LICENSE file. + +enum runtimeFunc: str { + arrayCmp: "arrayCmp", +} + +fn runtimeFindFn(mut &runtime: &ImportInfo, ident: runtimeFunc): &Fn { + const Binded = false + mut f := runtime.FindFn(ident, Binded) + if f == nil { + panic("runtime function is not exist, this is an implementation mistake, this panic call should be unreachable") + } + ret f +} \ No newline at end of file diff --git a/std/jule/sema/sema.jule b/std/jule/sema/sema.jule index 39e413cd4..3bc3d26da 100644 --- a/std/jule/sema/sema.jule +++ b/std/jule/sema/sema.jule @@ -208,6 +208,7 @@ unsafe fn pushSuggestion(mut log: *Log, fmt: LogMsg, args: ...any) { struct commonSemaMeta { comptimeTypeInfos: []&comptimeTypeInfo + runtime: &ImportInfo // Implicitly imported [std::runtime] package. } impl commonSemaMeta { @@ -2292,6 +2293,31 @@ impl Sema { ret nil } + // Checks new generics function instance. + // If instance is already exist, f will point to exist instantantiation. + fn checkGenericFn(mut &self, mut &f: &FnIns, mut &et: &Token): (ok: bool, exist: bool) { + ok = self.reloadFnInsTypes(f) + f.reloaded = true + if !ok { + ret false, false + } + mut existInstance := f.Decl.appendInstance(f) + // TODO: [check] is possible to optimize here using same environment with realoadFnInsTypes? + if !self.checkConstraintsFn(f, et, existInstance) { + ret false, false + } + if existInstance != nil { + // Set f to exist one. + f = existInstance + exist = true + } else { + // Check generic function instance instantly. + self.checkFnInsCaller(f, et) + } + ok = true + ret + } + fn checkTypeMethod(mut &self, mut &s: &StructIns, mut &f: &Fn) { // Generic instances are checked instantly. if len(f.Generics) > 0 { @@ -2417,6 +2443,27 @@ impl Sema { if !ok { ret false } + + // See implicit imports reference (1). + // If structure instance is comparable and have not custom compare method, + // compiler will use default compare method. If There is array field, + // push instance for runtime function. + if s.Comparable && s.Operators.Eq == nil { + mut decl := runtimeFindFn(self.meta.runtime, runtimeFunc.arrayCmp) + for (_, mut field) in s.Fields { + mut arr := field.Kind.Arr() + if arr == nil { + continue + } + mut f := decl.instanceForce() + f.Generics = append(f.Generics, &InsGeneric{Kind: arr.Elem}) + ok, _ = self.checkGenericFn(f, field.Decl.Token) + if !ok { + panic("arrayCmp evaluation failed, this is an implementation mistake") + } + } + } + for (_, mut f) in s.Methods { if len(f.Generics) == 0 { if self.readyToCheckFn(s, f) == nil { diff --git a/std/jule/sema/symbol.jule b/std/jule/sema/symbol.jule index cee98d321..7f7a7c854 100644 --- a/std/jule/sema/symbol.jule +++ b/std/jule/sema/symbol.jule @@ -417,7 +417,7 @@ impl symbolBuilder { ret &ImportInfo{ ImportAll: decl.Full, - Token: decl.Token, + Token: decl.Token, // Use decl token for correct implementation. See developer refernece (9). Path: path, LinkPath: decl.LinkPath, Ident: ident, @@ -495,18 +495,30 @@ impl symbolBuilder { } } - fn checkDuplicateUseDecl(mut self, &pkg: &ImportInfo): (ok: bool) { - // Find package by path to detect cpp header imports. - lpkg := self.table.SelectPackage(fn(spkg: &ImportInfo): bool { + fn findUseDecl(mut self, &pkg: &ImportInfo): &ImportInfo { + ret self.table.SelectPackage(fn(spkg: &ImportInfo): bool { + // Find package by path to detect cpp header imports. ret unsafe { pkg.Path == spkg.Path } }) + } + + fn checkDuplicateUseDecl(mut self, mut &pkg: &ImportInfo): (ok: bool, implicit: bool) { + mut lpkg := self.findUseDecl(pkg) if lpkg == nil { - ret true + ret true, false + } + + // See developer reference (9). + if isImplicitImport(lpkg) { + // Imported same package by source code. Update token. + // See developer reference (9.5). + lpkg.Token = pkg.Token + ret true, true } self.pushErr(pkg.Token, LogMsg.DuplicateUseDecl, pkg.LinkPath) self.pushSuggestion(LogMsg.RemoveUseDeclAvoidDuplication) - ret false + ret false, false } fn implImportSelections(mut self, mut &imp: &ImportInfo, mut &decl: &UseDecl) { @@ -665,13 +677,19 @@ impl symbolBuilder { ret nil } - mut ok := self.checkDuplicateUseDecl(imp) + mut ok, implicit := self.checkDuplicateUseDecl(imp) if !ok { ret nil } ok = self.importPackage(imp, decl) - self.table.Imports = append(self.table.Imports, imp) + if !implicit { + // Duplication analysis returns true, but actually it is duplication. + // Implicit import detected. + // Do not check and push again to imports. + // See developer reference (9.2). + self.table.Imports = append(self.table.Imports, imp) + } if ok { self.importer.Imported(imp) ret imp @@ -779,4 +797,10 @@ impl symbolBuilder { ret } } +} + +// Reports whether imp is implicitly imported. +// See developer reference (9). +fn isImplicitImport(imp: &ImportInfo): bool { + ret imp.Token == nil } \ No newline at end of file diff --git a/std/runtime/array.jule b/std/runtime/array.jule new file mode 100644 index 000000000..aced9d343 --- /dev/null +++ b/std/runtime/array.jule @@ -0,0 +1,23 @@ +// Copyright 2024 The Jule Programming Language. +// Use of this source code is governed by a BSD 3-Clause +// license that can be found in the LICENSE file. + +// Reports whether arrays are equal. +// Assumes array T have comparable elements. +// The type T always should be element type of arrays. +// This functions designed pointer based to reduce executable size. +// Avoid generation instance per array types such as [5]int and [4]int. +fn arrayCmp[T](mut a1: *T, mut a2: *T, n: int): bool { + if n == 0 { + ret true + } + end := a1 + n + for a1 < end { + if unsafe { *a1 != *a2 } { + ret false + } + a1++ + a2++ + } + ret true +} \ No newline at end of file