diff --git a/Julia.NET.sln b/Julia.NET.sln index a931d91..07df271 100644 --- a/Julia.NET.sln +++ b/Julia.NET.sln @@ -6,6 +6,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox", "Sandbox\Sandbox. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{9B099638-725B-441B-91EC-85BFE93A2ECD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox48", "Sandbox48\Sandbox48.csproj", "{DF199950-742F-4DA3-9170-AF5B097CDE70}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Julia.NETstandard", "Julia.NETstandard\Julia.NETstandard.csproj", "{614FED42-E1B9-4006-8D15-E96A974620FE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStandard", "TestStandard\TestStandard.csproj", "{564E4007-4138-4E80-830C-B8106099B649}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +30,17 @@ Global {9B099638-725B-441B-91EC-85BFE93A2ECD}.Debug|Any CPU.Build.0 = Debug|Any CPU {9B099638-725B-441B-91EC-85BFE93A2ECD}.Release|Any CPU.ActiveCfg = Release|Any CPU {9B099638-725B-441B-91EC-85BFE93A2ECD}.Release|Any CPU.Build.0 = Release|Any CPU + {DF199950-742F-4DA3-9170-AF5B097CDE70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF199950-742F-4DA3-9170-AF5B097CDE70}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF199950-742F-4DA3-9170-AF5B097CDE70}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF199950-742F-4DA3-9170-AF5B097CDE70}.Release|Any CPU.Build.0 = Release|Any CPU + {614FED42-E1B9-4006-8D15-E96A974620FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {614FED42-E1B9-4006-8D15-E96A974620FE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {614FED42-E1B9-4006-8D15-E96A974620FE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {614FED42-E1B9-4006-8D15-E96A974620FE}.Release|Any CPU.Build.0 = Release|Any CPU + {564E4007-4138-4E80-830C-B8106099B649}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {564E4007-4138-4E80-830C-B8106099B649}.Debug|Any CPU.Build.0 = Debug|Any CPU + {564E4007-4138-4E80-830C-B8106099B649}.Release|Any CPU.ActiveCfg = Release|Any CPU + {564E4007-4138-4E80-830C-B8106099B649}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Julia.NETstandard/Julia.NETstandard.csproj b/Julia.NETstandard/Julia.NETstandard.csproj new file mode 100644 index 0000000..eda4066 --- /dev/null +++ b/Julia.NETstandard/Julia.NETstandard.csproj @@ -0,0 +1,29 @@ + + + + netstandard2.0 + JuliadotNET + Johnathan Bizzano + https://github.com/HyperSphereStudio/JULIAdotNET + https://github.com/HyperSphereStudio/JULIAdotNET/blob/main/LICENSE + https://github.com/HyperSphereStudio/JULIAdotNET + JuliaNET + 10 + + + + true + x64 + + + + true + x64 + + + + + + + + diff --git a/Julia.NETstandard/generated/Core/JPrimitive.gen.cs b/Julia.NETstandard/generated/Core/JPrimitive.gen.cs new file mode 100644 index 0000000..0dcdbbb --- /dev/null +++ b/Julia.NETstandard/generated/Core/JPrimitive.gen.cs @@ -0,0 +1,139 @@ +using System; +using JuliaNET.Stdlib; + +namespace JuliaNET.Core +{ + public static partial class JPrimitive + { + public static JModule BaseM, CoreM, MainM; + public static JType ModuleT, TypeT, FunctionT, MethodT, UnionT, IntegerT, AbstractFloatT, StringT, PtrT, PermutedDimsArrayT; + public static JType BoolT, CharT, Float64T, Float32T, Int64T, Int32T, Int16T, Int8T, UInt64T, UInt32T, UInt16T, UInt8T, ArrayT; + public static Any sprintF, showerrorF, catch_backtraceF, stringF, getpropertyF, setpropertyNotF, namesF, makentupleF, writeSharpArrayF, maketupleF, ievalF, getindexF, setindexNotF, lengthF, iterateF, EqualityF, InequalityF, GreaterThanF, LessThanF, GreaterThanOrEqualF, LessThanOrEqualF, NotF, OnesComplementF, ExclusiveOrF, BitwiseAndF, BitwiseOrF, ModulusF, MultiplyF, AdditionF, SubtractionF, DivisionF, RightShiftF, LeftShiftF, typeofF, hashF, ismutableF, isabstracttypeF, isimmutableF, isprimitivetypeF, sizeofF, parentmoduleF, nameofF, fieldcountF, fieldnameF, fieldoffsetF, fieldtypeF; + + internal static unsafe void primitive_init() + { + Julia.Eval(@"module SharpModule begin + export makearray, maketuple, writeSharpArray, maketuple, ieval, union_types, makentuple + function method_argnames(m::Method) + argnames = ccall(:jl_uncompress_argnames, Vector{Symbol}, (Any,), m.slot_syms) + isempty(argnames) && return argnames + return [string(sym) for sym = (argnames[1:m.nargs])[2:end]] + end + ieval(mod::Module, ex) = begin + Core.eval(mod, Meta.parse(ex)) + end + maketuple(vals...) = begin + tuple(vals...) + end + (makentuple(::Type{T}, n, p::Ptr{Cvoid}) where T) = begin + p2 = convert(Ptr{T}, p) + return ntuple((i->begin + unsafe_load(p2, i) + end), n) + end + linedEvaluation(s::String, file::String, m::Module) = begin + Core.eval(m, Meta.parseall(s, filename = file)) + end + function writeSharpArray(p, arr) + ptr = convert(Ptr{Any}, p) + for i = eachindex(arr) + unsafe_store!(ptr, arr[i], i) + end + end +end end; using .SharpModule"); + + var writeSharpArray = Julia.Eval("writeSharpArray"); + fixed (Any* values = new Any[72]) + { + var syms = Julia.Eval("[Base,Core,Main,sprint,showerror,catch_backtrace,string,getproperty,setproperty!,names,makentuple,writeSharpArray,maketuple,ieval,getindex,setindex!,length,iterate,Module,Type,Function,Method,Union,Integer,AbstractFloat,String,Ptr,==,!=,>,<,>=,<=,!,~,^,&,|,rem,*,+,-,/,>>,<<,typeof,hash,ismutable,isabstracttype,isimmutable,isprimitivetype,sizeof,parentmodule,nameof,fieldcount,fieldname,fieldoffset,fieldtype,PermutedDimsArray,Bool,Char,Float64,Float32,Int64,Int32,Int16,Int8,UInt64,UInt32,UInt16,UInt8,Array]"); + writeSharpArray.Invoke(new Any(values), syms); + BaseM = values[0]; + CoreM = values[1]; + MainM = values[2]; + ModuleT = values[18]; + TypeT = values[19]; + FunctionT = values[20]; + MethodT = values[21]; + UnionT = values[22]; + IntegerT = values[23]; + AbstractFloatT = values[24]; + StringT = values[25]; + PtrT = values[26]; + PermutedDimsArrayT = values[58]; + sprintF = values[3]; + showerrorF = values[4]; + catch_backtraceF = values[5]; + stringF = values[6]; + getpropertyF = values[7]; + setpropertyNotF = values[8]; + namesF = values[9]; + makentupleF = values[10]; + writeSharpArrayF = values[11]; + maketupleF = values[12]; + ievalF = values[13]; + getindexF = values[14]; + setindexNotF = values[15]; + lengthF = values[16]; + iterateF = values[17]; + EqualityF = values[27]; + InequalityF = values[28]; + GreaterThanF = values[29]; + LessThanF = values[30]; + GreaterThanOrEqualF = values[31]; + LessThanOrEqualF = values[32]; + NotF = values[33]; + OnesComplementF = values[34]; + ExclusiveOrF = values[35]; + BitwiseAndF = values[36]; + BitwiseOrF = values[37]; + ModulusF = values[38]; + MultiplyF = values[39]; + AdditionF = values[40]; + SubtractionF = values[41]; + DivisionF = values[42]; + RightShiftF = values[43]; + LeftShiftF = values[44]; + typeofF = values[45]; + hashF = values[46]; + ismutableF = values[47]; + isabstracttypeF = values[48]; + isimmutableF = values[49]; + isprimitivetypeF = values[50]; + sizeofF = values[51]; + parentmoduleF = values[52]; + nameofF = values[53]; + fieldcountF = values[54]; + fieldnameF = values[55]; + fieldoffsetF = values[56]; + fieldtypeF = values[57]; + BoolT = values[59]; + CharT = values[60]; + Float64T = values[61]; + Float32T = values[62]; + Int64T = values[63]; + Int32T = values[64]; + Int16T = values[65]; + Int8T = values[66]; + UInt64T = values[67]; + UInt32T = values[68]; + UInt16T = values[69]; + UInt8T = values[70]; + ArrayT = values[71]; + + RegisterPrimitive(typeof(bool), BoolT); + RegisterPrimitive(typeof(char), CharT); + RegisterPrimitive(typeof(double), Float64T); + RegisterPrimitive(typeof(float), Float32T); + RegisterPrimitive(typeof(long), Int64T); + RegisterPrimitive(typeof(int), Int32T); + RegisterPrimitive(typeof(short), Int16T); + RegisterPrimitive(typeof(sbyte), Int8T); + RegisterPrimitive(typeof(ulong), UInt64T); + RegisterPrimitive(typeof(uint), UInt32T); + RegisterPrimitive(typeof(ushort), UInt16T); + RegisterPrimitive(typeof(byte), UInt8T); + RegisterPrimitive(typeof(Array), ArrayT); + } + } + } +} \ No newline at end of file diff --git a/Julia.NETstandard/generators/Core/JPrimitive.jl b/Julia.NETstandard/generators/Core/JPrimitive.jl new file mode 100644 index 0000000..bc0d938 --- /dev/null +++ b/Julia.NETstandard/generators/Core/JPrimitive.jl @@ -0,0 +1,147 @@ +#Used for Parser Validation +SharpModule = quote + export makearray, maketuple, writeSharpArray, maketuple, ieval, union_types, makentuple + + function method_argnames(m::Method) + argnames = ccall(:jl_uncompress_argnames, Vector{Symbol}, (Any,), m.slot_syms) + isempty(argnames) && return argnames + return [string(sym) for sym in argnames[1:m.nargs][2:end]] + end + + ieval(mod::Module, ex) = Core.eval(mod, Meta.parse(ex)) + maketuple(vals...) = tuple(vals...) + makentuple(::Type{T}, n, p::Ptr{Cvoid}) where T = (p2 = convert(Ptr{T}, p); return ntuple(i -> unsafe_load(p2, i), n)) + linedEvaluation(s::String, file::String, m::Module) = Core.eval(m, Meta.parseall(s, filename=file)) + + function writeSharpArray(p, arr) + ptr = convert(Ptr{Any}, p) + for i in eachindex(arr) + unsafe_store!(ptr, arr[i], i) + end + end +end + +eval(SharpModule) + +symbols = [Base, Core, Main, + sprint, showerror, catch_backtrace, string, + getproperty, setproperty!, names, + makentuple, writeSharpArray, maketuple, ieval, + getindex, setindex!, length, iterate, + Module, Type, Function, Method, Union, Integer, AbstractFloat, String, Ptr, + ==, !=, >, <, >=, <=, !, ~, ^, &, |, %, *, +, -, /, >>, <<, + typeof, hash, + ismutable, isabstracttype, isimmutable, isprimitivetype, sizeof, parentmodule, nameof, + fieldcount, fieldname, fieldoffset, fieldtype, PermutedDimsArray] + +primitiveTypeConversions = [ + Bool => "bool", + Char => "char", + + Float64 => "double", + Float32 => "float", +# Float16 => "Half", + + Int64 => "long", + Int32 => "int", + Int16 => "short", + Int8 => "sbyte", + UInt64 => "ulong", + UInt32 => "uint", + UInt16 => "ushort", + UInt8 => "byte", + Array => "Array" +] + +function generate_primitives(project_root, src_root, gen_root) + + function write_expression(x) + buffer = IOBuffer() + Base.show_unquoted(buffer, Base.remove_linenums!(x)) + return String(take!(buffer)) + end + + function fix_name(f) + f = replace(string(f), + "+" => "Addition", + "-" => "Subtraction", + "*" => "Multiply", + "/" => "Division", + "%" => "Modulus", + "rem" => "Modulus", + "^" => "ExclusiveOr", + "&" => "BitwiseAnd", + "|" => "BitwiseOr", + "<<" => "LeftShift", + ">>" => "RightShift", + "==" => "Equality", + ">=" => "GreaterThanOrEqual", + "<=" => "LessThanOrEqual", + ">" => "GreaterThan", + "<" => "LessThan", + "!=" => "Inequality", + "--" => "Decrement", + "++" => "Increment", + "~" => "OnesComplement", + "!" => "Not") + f = replace(f, "!" => "") + return f + end + + count = 0 + modules = [] + functions = [] + types = [] + + for s in symbols + if s isa Module + push!(modules, (s, count)) + elseif s isa Function + push!(functions, (s, count)) + elseif s isa Type + push!(types, (s, count)) + end + count += 1 + end + + count += 1 + for v in primitiveTypeConversions + push!(symbols, v[1]) + end + + write_lines(kernel, array) = join(["$(kernel(m));" for m in array], "\n ") + + open("$gen_root/JPrimitive.gen.cs", "w") do io + write(io, """using System; + using JuliaNET.Stdlib; + + namespace JuliaNET.Core + { + public static partial class JPrimitive + { + public static JModule $(join(["$(m[1])M" for m in modules], ", ")); + public static JType $(join(["$(t[1])T" for t in types], ", ")); + public static JType $(join(["$(t)T" for t in symbols[count:end]], ", ")); + public static Any $(join(["$(fix_name(f[1]))F" for f in functions], ", ")); + + internal static unsafe void primitive_init() + { + Julia.Eval(@"module SharpModule $(write_expression(SharpModule)) end; using .SharpModule"); + + var writeSharpArray = Julia.Eval(\"writeSharpArray\"); + fixed (Any* values = new Any[$(length(symbols))]) + { + var syms = Julia.Eval(\"[$(join(symbols, ","))]\"); + writeSharpArray.Invoke(new Any(values), syms); + $(write_lines(m -> "$(m[1])M = values[$(m[2])]", modules)) + $(write_lines(t -> "$(t[1])T = values[$(t[2])]", types)) + $(write_lines(f -> "$(fix_name(f[1]))F = values[$(f[2])]", functions)) + $(write_lines(i -> "$(symbols[i])T = values[$(i-1)]", count:length(symbols))) + + $(write_lines(t -> "RegisterPrimitive(typeof($(t[2])), $(t[1])T)", primitiveTypeConversions)) + } + } + } + }""") + end +end diff --git a/Julia.NETstandard/generators/Generate.bat b/Julia.NETstandard/generators/Generate.bat new file mode 100644 index 0000000..506188c --- /dev/null +++ b/Julia.NETstandard/generators/Generate.bat @@ -0,0 +1,2 @@ + +julia Generator.jl \ No newline at end of file diff --git a/Julia.NETstandard/generators/Generator.jl b/Julia.NETstandard/generators/Generator.jl new file mode 100644 index 0000000..bb9db44 --- /dev/null +++ b/Julia.NETstandard/generators/Generator.jl @@ -0,0 +1,5 @@ +include("Core/JPrimitive.jl") + +project_root = pwd() * "/.." + +generate_primitives(project_root, "$project_root/src/Core", "$project_root/generated/Core") diff --git a/Julia.NETstandard/src/Core/Boot.cs b/Julia.NETstandard/src/Core/Boot.cs new file mode 100644 index 0000000..c919f87 --- /dev/null +++ b/Julia.NETstandard/src/Core/Boot.cs @@ -0,0 +1,47 @@ +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace JuliaNET.Core +{ + internal static class Boot + { + internal static void jl_init_code(Options options, + bool sharpInit) + { + if (sharpInit) + { + var arguments = options.Arguments.Where(arg => !string.IsNullOrWhiteSpace(arg)).ToArray(); + if (arguments.Length != 0) + { + int len = arguments.Length; + unsafe + { + var stringBytes = stackalloc byte*[arguments.Length]; + GCHandle[] handles = new GCHandle[arguments.Length]; + + for (int i = 0; i < arguments.Length; ++i) + { + handles[i] = GCHandle.Alloc(Encoding.ASCII.GetBytes(arguments[i]), GCHandleType.Pinned); + stringBytes[i] = (byte*)handles[i].AddrOfPinnedObject(); + } + + JuliaCalls.jl_parse_opts(ref len, &stringBytes); + + for (int i = 0; i < arguments.Length; i++) + { + handles[i].Free(); + } + } + } + + JuliaCalls.jl_init(); + } + + JPrimitive.primitive_init(); + JPrimitive.init_primitive_types(); + Julia.CheckExceptions(); + Julia.CheckExceptions(); + } + } +} diff --git a/Julia.NETstandard/src/Core/JArray.cs b/Julia.NETstandard/src/Core/JArray.cs new file mode 100644 index 0000000..4c14db6 --- /dev/null +++ b/Julia.NETstandard/src/Core/JArray.cs @@ -0,0 +1,236 @@ +using System; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using JuliaNET.Stdlib; + +namespace JuliaNET.Core +{ + public class ArrayEnumerator : IEnumerator + { + private Array array; + private int index; + private int endIndex; + private int startIndex; + private int[] _indices; + private bool _complete; + + public ArrayEnumerator(Array array) + { + this.array = array; + this.index = -1; + startIndex = 0; + endIndex = array.Length; + _indices = new int[array.Rank]; + int checkForZero = 1; + for (int i = 0; i < array.Rank; i++) + { + _indices[i] = array.GetLowerBound(i); + checkForZero *= array.GetLength(i); + } + + _indices[_indices.Length - 1]--; + _complete = (checkForZero == 0); + } + + private void IncArray() + { + int rank = array.Rank; + _indices[rank - 1]++; + for (int dim = rank - 1; dim >= 0; dim--) + { + if (_indices[dim] > array.GetUpperBound(dim)) + { + if (dim == 0) + { + _complete = true; + break; + } + + for (int j = dim; j < rank; j++) + _indices[j] = array.GetLowerBound(j); + _indices[dim - 1]++; + } + } + } + + public bool MoveNext() + { + if (_complete) + { + index = endIndex; + return false; + } + + index++; + IncArray(); + return !_complete; + } + + public object Current + { + get => array.GetValue(_indices); + set => array.SetValue(value, _indices); + } + + public int[] Index => _indices; + + public void Reset() + { + index = startIndex - 1; + int checkForZero = 1; + for (int i = 0; i < array.Rank; i++) + { + _indices[i] = array.GetLowerBound(i); + checkForZero *= array.GetLength(i); + } + + _complete = checkForZero == 0; + _indices[_indices.Length - 1]--; + } + } + + public struct JArray + { + private Any _ptr; + public int Length => (int)JPrimitive.lengthF.UnsafeInvoke(this); + public int Rank => JuliaCalls.jl_array_rank(_ptr); + public int Size(int d = 1) => (int)JuliaCalls.jl_array_size(_ptr, d); + public JType ElementType => JuliaCalls.jl_array_eltype(_ptr); + + public JArray(JType type, + long length) : this(JuliaCalls.jl_alloc_array_1d(JuliaCalls.jl_apply_array_type(type, 1), (nint)length)) + { + } + + public JArray(JType type, + long row, + long col) : this(JuliaCalls.jl_alloc_array_2d(JuliaCalls.jl_apply_array_type(type, 2), (nint)row, (nint)col)) + { + } + + public JArray(JType type, + long row, + long col, + long depth) : this(JuliaCalls.jl_alloc_array_3d(JuliaCalls.jl_apply_array_type(type, 3), (nint)row, (nint)col, (nint)depth)) + { + } + + public unsafe JArray(Array a, + bool own = false) + { + var elType = JType.GetJuliaTypeFromNetType(a.GetType().GetElementType()); + var aType = JuliaCalls.jl_apply_array_type(elType, a.Rank); + var ptr = GCHandle.Alloc(a, GCHandleType.Pinned).AddrOfPinnedObject(); + + if (a.Rank == 1) + _ptr = JuliaCalls.jl_ptr_to_array_1d(aType, ptr, a.Length, own ? 1 : 0); + else + { + long* dims = stackalloc long[a.Rank]; + for (int i = 0; i < a.Rank; i++) + dims[i] = a.GetLength(a.Rank - (i + 1)); + var dimT = JPrimitive.makentupleF.Invoke(JPrimitive.Int64T, a.Rank, new(dims)); + _ptr = JuliaCalls.jl_ptr_to_array(aType, ptr, dimT, own ? 1 : 0); + for (int i = 0; i < a.Rank; i++) + dims[i] = a.Rank - i; + dimT = JPrimitive.makentupleF.Invoke(JPrimitive.Int64T, a.Rank, new(dims)); + _ptr = JPrimitive.PermutedDimsArrayT.Create(_ptr, dimT); + } + } + + public JArray(IntPtr ptr) => _ptr = ptr; + + public static implicit operator IntPtr(JArray value) => value._ptr; + public static implicit operator JArray(IntPtr ptr) => new(ptr); + public static implicit operator JArray(Any ptr) => new(ptr); + public static implicit operator Any(JArray ptr) => new(ptr); + + public static JArray Alloc(JType elType, + int n) => JuliaCalls.jl_alloc_array_1d(JuliaCalls.jl_apply_array_type(elType, 1), n); + + public static JArray Alloc(JType elType, + int r, + int c) => JuliaCalls.jl_alloc_array_2d(JuliaCalls.jl_apply_array_type(elType, 2), r, c); + + public static JArray Alloc(JType elType, + int d, + int r, + int c) => JuliaCalls.jl_alloc_array_3d(JuliaCalls.jl_apply_array_type(elType, 3), d, r, c); + + public static unsafe JArray Alloc(JType elType, + params int[] dimensions) + { + var aType = JuliaCalls.jl_apply_array_type(elType, dimensions.Length); + if (dimensions.Length == 1) + return JuliaCalls.jl_alloc_array_1d(aType, dimensions[0]); + if (dimensions.Length == 2) return JuliaCalls.jl_alloc_array_2d(aType, dimensions[0], dimensions[1]); + if (dimensions.Length == 3) return JuliaCalls.jl_alloc_array_3d(aType, dimensions[0], dimensions[1], dimensions[2]); + fixed (int* p = dimensions) + { + var dimsTuple = JPrimitive.makentupleF.Invoke(JPrimitive.UInt32T, dimensions.Length, new(p)); + return JPrimitive.makentupleF.Invoke(aType, dimsTuple, dimensions.Length); + } + } + + #region NeededOverloadedOperators + + public static bool operator ==(JArray v, + JArray p) => v._ptr == p._ptr; + + public static bool operator !=(JArray v, + JArray p) => !(v == p); + + public override string ToString() => _ptr.ToString(); + public override int GetHashCode() => _ptr.GetHashCode(); + public override bool Equals(object o) => _ptr.Equals(o); + + #endregion + + public unsafe void Reshape(params int[] newDims) + { + var aType = JuliaCalls.jl_apply_array_type(ElementType, newDims.Length); + fixed (int* dims = newDims) + { + var dimsTuple = JPrimitive.makentupleF.Invoke(JPrimitive.UInt32T, newDims.Length, new(dims)); + _ptr = JuliaCalls.jl_reshape_array(aType, _ptr, dimsTuple); + } + } + + public Any this[Any idx] + { + get => _ptr[idx]; + set => _ptr[idx] = value; + } + + public Any this[Any i1, + Any i2] + { + get => _ptr[i1, i2]; + set => _ptr[i1, i2] = value; + } + + public Any this[Any i1, + Any i2, + Any i3] + { + get => _ptr[i1, i2, i3]; + set => _ptr[i1, i2, i3] = value; + } + + public Any this[Any i1, + Any i2, + Any i3, + Any i4] + { + get => _ptr[i1, i2, i3, i4]; + set => _ptr[i1, i2, i3, i4] = value; + } + + public Any this[Any[] args] + { + get => _ptr[args]; + set => _ptr[args] = value; + } + } +} diff --git a/Julia.NETstandard/src/Core/JEnumeration.cs b/Julia.NETstandard/src/Core/JEnumeration.cs new file mode 100644 index 0000000..8836d47 --- /dev/null +++ b/Julia.NETstandard/src/Core/JEnumeration.cs @@ -0,0 +1,55 @@ +using System.Collections; +using System.Collections.Generic; + +namespace JuliaNET.Core +{ + public interface JVal + { + internal T This { get; } + } + + public interface JEnumerable : + JVal, IEnumerable + where ObjectT : JEnumerable + { + internal void EnumerationReset(StateT s, + out StateT ns); + + internal EnumerableT EnumerationCurrent(StateT s); + + internal void EnumerationDispose(); + + internal bool EnumerationMoveNext(StateT s, + out StateT ns); + + internal IndexT EnumerationIndex(StateT s); + + // IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + // IEnumerator IEnumerable.GetEnumerator() => new JEnumerator(This); + } + + public struct JEnumerator : IEnumerator where ObjectT : JEnumerable + { + private readonly ObjectT _ptr; + private StateT _state; + public IndexT Index => _ptr.EnumerationIndex(_state); + + public JEnumerator(ObjectT ptr) + { + _ptr = ptr; + _state = default; + Reset(); + } + + public bool MoveNext() => _ptr.EnumerationMoveNext(_state, out _state); + + public void Reset() => _ptr.EnumerationReset(_state, out _state); + + public EnumerableT Current => _ptr.EnumerationCurrent(_state); + + object IEnumerator.Current => Current; + + public void Dispose() => _ptr.EnumerationDispose(); + } +} diff --git a/Julia.NETstandard/src/Core/JModule.cs b/Julia.NETstandard/src/Core/JModule.cs new file mode 100644 index 0000000..8631274 --- /dev/null +++ b/Julia.NETstandard/src/Core/JModule.cs @@ -0,0 +1,46 @@ +using JuliaNET.Stdlib; + +namespace JuliaNET.Core; + +public struct JModule +{ + private readonly Any _ptr; + + public string Name => ToString(); + + public JModule Parent => _ptr.Module; + + public JModule(Any ptr) => _ptr = ptr; + + public static implicit operator JModule(Any ptr) => new(ptr); + + public static implicit operator Any(JModule ptr) => new(ptr._ptr); + + #region Needed Overloaded Operators + + public static bool operator ==(JModule v, + JModule p) => v._ptr == p._ptr; + + public static bool operator !=(JModule v, + JModule p) => !(v == p); + + public override string ToString() => _ptr.ToString(); + + public override int GetHashCode() => _ptr.GetHashCode(); + + public override bool Equals(object o) => _ptr.Equals(o); + + #endregion + + public JType GetType(Any name) => Julia.GetGlobal(_ptr, name); + + public Any GetFunction(Any name) => Julia.GetGlobal(_ptr, name); + + public Any GetGlobal(Any name) => Julia.GetGlobal(_ptr, name); + + public JType GetType(string name) => Julia.GetGlobal(_ptr, Julia.Symbol(name)); + + public Any GetFunction(string name) => Julia.GetGlobal(_ptr, Julia.Symbol(name)); + + public Any GetGlobal(string name) => Julia.GetGlobal(_ptr, Julia.Symbol(name)); +} diff --git a/Julia.NETstandard/src/Core/JPrimitive.cs b/Julia.NETstandard/src/Core/JPrimitive.cs new file mode 100644 index 0000000..d1d6354 --- /dev/null +++ b/Julia.NETstandard/src/Core/JPrimitive.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; + +namespace JuliaNET.Core +{ + public static partial class JPrimitive + { + private static readonly Dictionary Sharp2Julia = new(); + private static readonly Dictionary Julia2Sharp = new(); + + private static void RegisterPrimitive(Type t, + JType type) + { + Sharp2Julia.Add(t, type); + Julia2Sharp.Add(type, t); + } + + public static JType FindJuliaPrimitiveEquivalent(Type t) + { + if (Sharp2Julia.TryGetValue(t, out var v)) + return v; + throw new Exception("No primitive Type for " + t + " Found!"); + } + + public static void init_primitive_types() + { + } + } +} diff --git a/Julia.NETstandard/src/Core/JType.cs b/Julia.NETstandard/src/Core/JType.cs new file mode 100644 index 0000000..2e5b570 --- /dev/null +++ b/Julia.NETstandard/src/Core/JType.cs @@ -0,0 +1,89 @@ +using System; +using JuliaNET.Stdlib; + +namespace JuliaNET.Core +{ + public enum JTypeType : byte + { + Struct, + MutableStruct, + Abstract, + Primitive, + Union + } + + public struct JType + { + private readonly Any _ptr; + public string Name => ToString(); + public JModule Module => _ptr.Module; + public bool IsMutable => (bool)JPrimitive.ismutableF.Invoke(this); + public bool IsImmutable => (bool)JPrimitive.isimmutableF.Invoke(this); + public bool IsAbstract => (bool)JPrimitive.isabstracttypeF.Invoke(this); + public bool IsPrimitive => (bool)JPrimitive.isprimitivetypeF.Invoke(this); + public bool IsUnion => ((JType)JPrimitive.typeofF.Invoke(this) == JPrimitive.UnionT); + public int SizeOf => (int)JPrimitive.sizeofF.Invoke(this); + public int FieldCount => (int)JPrimitive.fieldcountF.Invoke(this); + + public JTypeType Type + { + get + { + if (IsPrimitive) + return JTypeType.Primitive; + if (IsAbstract) + return JTypeType.Abstract; + if (IsMutable) + return JTypeType.MutableStruct; + if (IsImmutable) + return JTypeType.Struct; + throw new Exception("Unable to determine type of " + this); + } + } + + public JType(Any ptr) => _ptr = ptr; + + public static implicit operator JType(Any ptr) => new(ptr); + + public static implicit operator Any(JType ptr) => new(ptr._ptr); + + // public Any Create(params Any[] values) => _ptr.Invoke(values); + + public Any Create() => _ptr.Invoke(); + + public Any Create(Any val) => _ptr.Invoke(val); + + public Any Create(Any val1, + Any val2) => _ptr.Invoke(val1, val2); + + public Any Create(Any val1, + Any val2, + Any val3) => _ptr.Invoke(val1, val2, val3); + + public bool IsType(Any val) => Julia.Isa(val, this); + + public static bool operator ==(JType v, + JType p) => JuliaCalls.jl_types_equal(v, p) != 0; + + public static bool operator !=(JType v, + JType p) => !(v == p); + + #region Needed Overloaded Operators + + public override string ToString() => _ptr.ToString(); + + public override int GetHashCode() => _ptr.GetHashCode(); + + public override bool Equals(object o) => _ptr.Equals(o); + + #endregion + + public string FieldName(int i) => (string)JPrimitive.fieldnameF.Invoke(this, i); + + public int FieldOffset(int i) => (int)JPrimitive.fieldoffsetF.Invoke(this, i); + + public JType FieldType(int i) => JPrimitive.fieldtypeF.Invoke(this, i); + + public static JType GetJuliaTypeFromNetType(Type t) => JPrimitive.FindJuliaPrimitiveEquivalent(t); + } +} diff --git a/Julia.NETstandard/src/Core/Julia.cs b/Julia.NETstandard/src/Core/Julia.cs new file mode 100644 index 0000000..3568bae --- /dev/null +++ b/Julia.NETstandard/src/Core/Julia.cs @@ -0,0 +1,175 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using JuliaNET.Stdlib; +using JuliaNET.Utils; + +namespace JuliaNET.Core +{ + public class Julia + { + public static bool IsInitialized { get; private set; } + + private static string _juliaDir; + + public static bool PreviouslyLoaded { get; private set; } + + private static object _gclock = new(); + + public static string LibDirectory => MString(JuliaCalls.jl_get_libdir()); + + public static bool IsInstalled => JuliaDir != null; + + public static string JuliaDir + { + get + { + if (_juliaDir == null) + _juliaDir = JuliaUtils.GetJuliaDir(); + return _juliaDir; + } + set => _juliaDir = value; + } + + public static void Init() => Init(new Options()); + + public static void Init(Options options) => Init(options, true); + + internal static void Init(Options options, + bool sharpInit) + { + if (IsInitialized) return; + IsInitialized = true; + + var startTime = DateTime.Now; + var memSize = GC.GetTotalMemory(false); + + if (PreviouslyLoaded) + throw new InvalidOperationException("Cannot Close And Reopen Julia in the Same Process"); + + try + { + options.BuildArguments(); + var env = Environment.CurrentDirectory; + Environment.CurrentDirectory = options.JuliaDirectory; + JuliaDll.Open(); + Boot.jl_init_code(options, sharpInit); + Environment.CurrentDirectory = env; + PreviouslyLoaded = true; + + var time = DateTime.Now - startTime; + var bytes = GC.GetTotalMemory(false) - memSize; + Console.WriteLine("Initialized Julia.NET in " + time.Milliseconds + " ms and " + bytes + " bytes"); + } + catch (Exception) + { + Console.WriteLine("Failed To Initialize Julia.NET!"); + throw; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] // | MethodImplOptions.AggressiveOptimization)] + public static bool Isa(Any v, + Any t) => JuliaCalls.jl_isa(v, t) != 0; + + public static void SetGlobal(Any m, + string sym, + Any val) => SetGlobal(m, JuliaCalls.jl_symbol(sym), val); + + public static void SetGlobal(Any m, + Any sym, + Any val) + { + JuliaCalls.jl_set_global(m, sym, val); + CheckExceptions(); + } + + public static Any GetGlobal(Any m, + Any sym) + { + var val = JuliaCalls.jl_get_global(m, sym); + CheckExceptions(); + return val; + } + + public static Any Symbol(string str) => JuliaCalls.jl_symbol(str); + + public static Any GetGlobal(Any m, + string sym) => GetGlobal(m, Symbol(sym)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] // | MethodImplOptions.AggressiveOptimization)] + public static void CheckExceptions() + { + if (JuliaCalls.jl_exception_occurred() != IntPtr.Zero) + throw new JuliaException(JuliaCalls.jl_exception_occurred()); + } + + public static void Exit(int code = 0) + { + if (!IsInitialized) return; + IsInitialized = false; + + Console.WriteLine("Disposing Julia.NET"); + JuliaCalls.jl_atexit_hook(code); + JuliaDll.Close(); + } + + public static Any Eval(string str) + { + var val = JuliaCalls.jl_eval_string(str); + CheckExceptions(); + return val; + } + + public static Any Eval(string str, + Any module) => JPrimitive.ievalF.Invoke(str, module); + + public static void PUSH_GC(Any[] values) + { + lock (_gclock) JuliaGC.JL_GC_PUSHARGS(values); + } + + public static void PUSH_GC(Any a1) => PUSH_GC(new Any[] { a1 }); + + public static void PUSH_GC(Any a1, + Any a2) => PUSH_GC(new Any[] { a1, a2 }); + + public static void PUSH_GC(Any a1, + Any a2, + Any a3) => PUSH_GC(new Any[] { a1, a2, a3 }); + + public static void PUSH_GC(Any a1, + Any a2, + Any a3, + Any a4) => PUSH_GC(new Any[] { a1, a2, a3, a4 }); + + public static void POP_GC() + { + lock (_gclock) JuliaGC.JL_GC_POP(); + } + + public static string UnboxString(Any val) => Marshal.PtrToStringAnsi(JuliaCalls.jl_string_ptr(val)); + // public static unsafe Any AllocStruct(Any type, Any[] vals) => JuliaCalls.jl_new_structv(type, vals.ToPointer(), (uint) vals.Length); + + private static string MString(IntPtr p) + { + CheckExceptions(); + return Marshal.PtrToStringAnsi(p); + } + } + + + public class CSharp + { +#if NET + [UnmanagedCallersOnly] +#endif + public static int Init(IntPtr julia_bindir) + { + var jo = new Options(); + jo.JuliaDirectory = Marshal.PtrToStringUni(julia_bindir); + Julia.Init(jo, false); + return 0; + } + } +} diff --git a/Julia.NETstandard/src/Core/JuliaCalls.cs b/Julia.NETstandard/src/Core/JuliaCalls.cs new file mode 100644 index 0000000..2ec5f58 --- /dev/null +++ b/Julia.NETstandard/src/Core/JuliaCalls.cs @@ -0,0 +1,680 @@ +using System; +using System.Runtime.InteropServices; +using JuliaNET.Stdlib; + +//Written By Johnathan Bizzano +namespace JuliaNET.Core +{ + public class JuliaCalls + { + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_init(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern unsafe void jl_parse_opts(ref int argc, + byte*** argvp); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_eval_string(string c); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_atexit_hook(int hook); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_string_ptr(IntPtr v); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern double jl_unbox_float64(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern float jl_unbox_float32(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern long jl_unbox_int64(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_unbox_int32(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern short jl_unbox_int16(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern sbyte jl_unbox_int8(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern bool jl_unbox_bool(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern ulong jl_unbox_uint64(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern uint jl_unbox_uint32(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern ushort jl_unbox_uint16(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern byte jl_unbox_uint8(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_unbox_voidpointer(IntPtr v); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_float64(double t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_float32(float t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_int64(long t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_int32(int t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_int16(short t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_int8(sbyte t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_bool(bool t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_uint64(ulong t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_uint32(uint t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_uint16(ushort t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_uint8(byte t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_box_voidpointer(IntPtr x); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_cstr_to_string(string s); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern Any jl_call(Any f, + Any* args, + Int32 arg_count); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern Any jl_call0(Any f); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern Any jl_call1(Any f, + Any arg1); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern Any jl_call2(Any f, + Any arg1, + Any arg2); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern Any jl_call3(Any f, + Any arg1, + Any arg2, + Any arg3); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern Any jl_get_global(Any m, + Any var); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern Any jl_symbol(string sym); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_types_equal(JType v1, + JType v2); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_exception_occurred(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_current_exception(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_exception_clear(); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_typename_str(IntPtr val); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_typeof_str(IntPtr v); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_new_module(IntPtr name); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_set_module_nospecialize(IntPtr self, + int on); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_set_module_optlevel(IntPtr self, + int lvl); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_get_module_optlevel(IntPtr m); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_set_module_compile(IntPtr self, + int value); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_get_module_compile(IntPtr m); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_set_module_infer(IntPtr self, + int value); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_get_module_infer(IntPtr m); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_get_binding(IntPtr m, + IntPtr var); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_get_binding_or_error(IntPtr m, + IntPtr var); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_module_globalref(IntPtr m, + IntPtr var); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_get_binding_wr(IntPtr m, + IntPtr var, + int error); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_get_binding_for_method_def(IntPtr m, + IntPtr var); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_boundp(IntPtr m, + IntPtr var); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_defines_or_exports_p(IntPtr m, + IntPtr var); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_binding_resolved_p(IntPtr m, + IntPtr var); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_is_const(Any m, + Any sym); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_set_global(IntPtr m, + IntPtr var, + IntPtr val); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_set_const(IntPtr m, + IntPtr var, + IntPtr val); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_checked_assignment(IntPtr b, + IntPtr rhs); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_declare_constant(IntPtr b); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_module_using(IntPtr to, + IntPtr from); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_module_use(IntPtr to, + IntPtr from, + IntPtr s); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_module_use_as(IntPtr to, + IntPtr from, + IntPtr s, + IntPtr asname); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_module_import(IntPtr to, + IntPtr from, + IntPtr s); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_module_import_as(IntPtr to, + IntPtr from, + IntPtr s, + IntPtr asname); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_module_export(IntPtr from, + IntPtr s); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_is_imported(IntPtr m, + IntPtr s); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_module_exports_p(IntPtr m, + IntPtr var); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_add_standard_imports(IntPtr m); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_eqtable_put(IntPtr h, + IntPtr key, + IntPtr val, + IntPtr inserted); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_eqtable_get(IntPtr h, + IntPtr key, + IntPtr deflt); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_errno(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_set_errno(int e); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern Int32 jl_stat(string path, + string statbuf); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_cpu_threads(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern long jl_getpagesize(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern long jl_getallocationgranularity(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_is_debugbuild(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_get_UNAME(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_get_ARCH(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_get_libllvm(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_environ(int i); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_error(string str); + + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_too_few_args(string fname, + int min); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_too_many_args(string fname, + int max); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_type_error(string fname, + IntPtr expected, + IntPtr got); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_type_error_rt(string fname, + string context, + IntPtr ty, + IntPtr got); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_undefined_var_error(IntPtr var); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_atomic_error(string str); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_bounds_error(IntPtr v, + IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_bounds_error_v(IntPtr v, + IntPtr[] idxs, + nint nidxs); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_bounds_error_int(IntPtr v, + nint i); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_bounds_error_tuple_int(IntPtr[] v, + nint nv, + nint i); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_bounds_error_unboxed_int(IntPtr v, + IntPtr vt, + nint i); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_bounds_error_ints(IntPtr v, + uint[] idxs, + nint nidxs); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_eof_error(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_get_libdir(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_init_with_image(string julia_bindir, + string image_relative_path); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_get_default_sysimg_path(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_is_initialized(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_exit(int status); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_pathname_for_handle(IntPtr handle); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_deserialize_verify_header(IntPtr s); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_preload_sysimg_so(string fname); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_set_sysimg_so(IntPtr handle); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_create_system_image(IntPtr p); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_save_system_image(string fname); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_restore_system_image(string fname); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_restore_system_image_data(string buf, + nint len); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_save_incremental(string fname, + IntPtr worklist); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_restore_incremental(string fname, + IntPtr depmods); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_restore_incremental_from_buf(string buf, + nint sz, + IntPtr depmods); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_expand(IntPtr expr, + IntPtr inmodule); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_expand_with_loc(IntPtr expr, + IntPtr inmodule, + string file, + int line); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_expand_with_loc_warn(IntPtr expr, + IntPtr inmodule, + string file, + int line); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_expand_in_world(IntPtr expr, + IntPtr inmodule, + string file, + int line, + nint world); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_expand_stmt(IntPtr expr, + IntPtr inmodule); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_expand_stmt_with_loc(IntPtr expr, + IntPtr inmodule, + string file, + int line); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_load_dynamic_library(string fname, + nint flags, + int throw_err); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_dlopen(string filename, + nint flags); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_dlclose(IntPtr handle); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_dlsym(IntPtr handle, + string symbol, + IntPtr[] value, + int throw_err); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_is_operator(string sym); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_is_unary_operator(string sym); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_is_unary_and_binary_operator(string sym); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_is_syntactic_operator(string sym); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_operator_precedence(string sym); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_yield(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_new_task(IntPtr f, + IntPtr v, + nint p); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern void jl_switchto(IntPtr[] pt); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern int jl_set_task_tid(IntPtr[] task, + int tid); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_throw(IntPtr e); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_rethrow(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_sig_throw(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_rethrow_other(IntPtr e); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_no_exc_handler(IntPtr e); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_gc_enable(int on); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_gc_is_enabled(); + + public enum JLGCCollection + { + JL_GC_AUTO = 0, // use heuristics to determine the collection type + JL_GC_FULL = 1, // force a full collection + JL_GC_INCREMENTAL = 2, // force an incremental collection + }; + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_gc_collect(JLGCCollection c); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_gc_add_finalizer(IntPtr v, + IntPtr f); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_gc_add_ptr_finalizer(IntPtr ptls, + IntPtr v, + IntPtr f); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_finalize(IntPtr o); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_gc_new_weakref(IntPtr value); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_gc_alloc_0w(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_gc_alloc_1w(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_gc_alloc_2w(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_gc_alloc_3w(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_gc_allocobj(nint sz); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern IntPtr jl_malloc_stack(uint* bufsz, + IntPtr owner); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_free_stack(IntPtr stkbuf, + nint bufsz); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_gc_use(IntPtr a); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void jl_clear_malloc_data(); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_gc_managed_malloc(nint sz); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_subtype(IntPtr a, + IntPtr b); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_isa(IntPtr a, + IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern JArray jl_new_array(JType atype, + JArray dims); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern JArray jl_reshape_array(JType atype, + JArray data, + JArray dims); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern JArray jl_ptr_to_array_1d(JType atype, + IntPtr data, + nint nel, + int ownBuffer); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern JArray jl_ptr_to_array(JType atype, + IntPtr data, + Any dims, + int ownBuffer); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern JType jl_apply_array_type(JType type, + nint dim); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_array_ptr(JArray a); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern JType jl_array_eltype(IntPtr a); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern int jl_array_rank(IntPtr a); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern nint jl_array_size(IntPtr a, + int d); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern JArray jl_alloc_array_1d(JType atype, + nint nr); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern JArray jl_alloc_array_2d(JType atype, + nint nr, + nint nc); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern JArray jl_alloc_array_3d(JType atype, + nint nr, + nint nc, + nint z); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern unsafe IntPtr jl_new_structv(IntPtr type, + Any* args, + UInt32 na); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern unsafe IntPtr jl_apply_tuple_type_v(IntPtr* types, + nint nc); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr jl_new_struct_uninit(IntPtr t); + + [DllImport("libjulia.dll", CallingConvention = CallingConvention.Cdecl)] + public static unsafe extern IntPtr* jl_get_pgcstack(); + } +} diff --git a/Julia.NETstandard/src/Core/JuliaDll.cs b/Julia.NETstandard/src/Core/JuliaDll.cs new file mode 100644 index 0000000..38546e0 --- /dev/null +++ b/Julia.NETstandard/src/Core/JuliaDll.cs @@ -0,0 +1,30 @@ +using System; +using System.Runtime.InteropServices; + +namespace JuliaNET.Core +{ + public class JuliaDll + { + private static IntPtr JuliaLib; + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern IntPtr LoadLibrary(string lib); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern void FreeLibrary(IntPtr module); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern IntPtr GetProcAddress(IntPtr module, + string proc); + + internal static void Open() => LoadLibrary("libjulia.dll"); + + public static IntPtr GetFunction(string name) => JuliaLib == IntPtr.Zero ? IntPtr.Zero : GetProcAddress(JuliaLib, name); + + internal static void Close() + { + FreeLibrary(JuliaLib); + JuliaLib = IntPtr.Zero; + } + } +} diff --git a/Julia.NETstandard/src/Core/JuliaException.cs b/Julia.NETstandard/src/Core/JuliaException.cs new file mode 100644 index 0000000..efd1f95 --- /dev/null +++ b/Julia.NETstandard/src/Core/JuliaException.cs @@ -0,0 +1,28 @@ +using System; +using JuliaNET.Stdlib; + +//Written by Johnathan Bizzano +namespace JuliaNET.Core +{ + public class JuliaException : Exception + { + private static string GetMessage(Any ptr) + { + try + { + return "JuliaException(\"" + JPrimitive.sprintF + .UnsafeInvoke(JPrimitive.showerrorF, ptr, JPrimitive.catch_backtraceF.UnsafeInvoke()) + .UnboxString() + "\")"; + } + catch (Exception e) + { + Console.WriteLine("Error Writing Exception To Console!"); + Console.WriteLine(e); + Console.WriteLine(ptr.ToString()); + throw; + } + } + + public JuliaException(Any excep) : base(GetMessage(excep)) => JuliaCalls.jl_exception_clear(); + } +} diff --git a/Julia.NETstandard/src/Core/JuliaGC.cs b/Julia.NETstandard/src/Core/JuliaGC.cs new file mode 100644 index 0000000..99f935e --- /dev/null +++ b/Julia.NETstandard/src/Core/JuliaGC.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.InteropServices; +using JuliaNET.Stdlib; +using JuliaNET.Utils; + +namespace JuliaNET.Core; + +// ReSharper disable once InconsistentNaming +public static class JuliaGC { + private static readonly UnsafeStream jl_gc_frames = new(); + private static unsafe _jl_gcframe_t** CurrentFrame = (_jl_gcframe_t**) JuliaCalls.jl_get_pgcstack(); + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct _jl_gcframe_t { + public nint nroots; + public _jl_gcframe_t* prev; + + public _jl_gcframe_t(_jl_gcframe_t* lastFrame, int len) { + nroots = len << 2; + prev = lastFrame; + } + } + + public static unsafe void JL_GC_PUSHARGS(Any[] v) { + jl_gc_frames.EnsureSizeWrite(jl_gc_frames.Count + v.Length * sizeof(nint) + sizeof(_jl_gcframe_t)); + var f = new _jl_gcframe_t(*CurrentFrame, v.Length); + *CurrentFrame = (_jl_gcframe_t*) jl_gc_frames.Begin; + jl_gc_frames.Write(f); + var ptr = (IntPtr*) jl_gc_frames.Begin; + foreach (var t in v) + *ptr++ = t; + } + + public static unsafe void JL_GC_POP() => *CurrentFrame = (*CurrentFrame)->prev; +} diff --git a/Julia.NETstandard/src/Core/Options.cs b/Julia.NETstandard/src/Core/Options.cs new file mode 100644 index 0000000..76c3595 --- /dev/null +++ b/Julia.NETstandard/src/Core/Options.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; + +namespace JuliaNET.Core +{ + public class Options + { + public string JuliaDirectory; + + public List Arguments = new(); + + public int ThreadCount = 1; + + public int WorkerCount = 1; + + public int Optimize = 2; + + public string LoadSystemImage; + + public string EvaluationString; + + public bool UseSystemImageNativeCode = true; + + public bool HandleSignals = true; + + public bool PrecompileModules = true; + + public void Add(params object[] args) + { + foreach (var arg in args) + Arguments.Add(arg.ToString()); + } + + private string AsJLString(bool b) => b ? "yes" : "no"; + + internal void BuildArguments() + { + Add(""); + + if (ThreadCount != 1) + Add("-t", ThreadCount); + + if (WorkerCount != 1) + Add("-p", WorkerCount); + + if (Optimize != 2) + Add("-O", Optimize); + + if (EvaluationString != null) + Add("-e", EvaluationString); + + if (LoadSystemImage != null) + Add("-J", LoadSystemImage); + + if (!UseSystemImageNativeCode) + Add("--sysimage-native-code=", AsJLString(UseSystemImageNativeCode)); + + if (!PrecompileModules) + Add("--compiled-modules=", AsJLString(PrecompileModules)); + + if (!HandleSignals) + Add("--handle-signals =", AsJLString(PrecompileModules)); + + if (JuliaDirectory != null) + Julia.JuliaDir = JuliaDirectory; + else JuliaDirectory = Julia.JuliaDir; + + if (JuliaDirectory == null) + throw new Exception("Julia Path Not Found"); + } + } +} diff --git a/Julia.NETstandard/src/Dynamics/DyAny.cs b/Julia.NETstandard/src/Dynamics/DyAny.cs new file mode 100644 index 0000000..00ab760 --- /dev/null +++ b/Julia.NETstandard/src/Dynamics/DyAny.cs @@ -0,0 +1,64 @@ +using System.Dynamic; +using System.Linq.Expressions; +using System.Reflection; +using JuliaNET.Core; +using JuliaNET.Stdlib; + +namespace JuliaNET.Dynamics +{ + public class DyAny : IDynamicMetaObjectProvider + { + internal readonly Any Ptr; + + public DyAny(Any ptr) => Ptr = ptr; + + public DynamicMetaObject GetMetaObject(Expression parameter) => new JuliaDynamic(parameter, this); + + #region Conversions + + public static explicit operator long(DyAny value) => (long)value.Ptr; + public static explicit operator ulong(DyAny value) => (ulong)value.Ptr; + public static explicit operator int(DyAny value) => (int)value.Ptr; + public static explicit operator uint(DyAny value) => (uint)value.Ptr; + public static explicit operator short(DyAny value) => (short)value.Ptr; + public static explicit operator ushort(DyAny value) => (ushort)value.Ptr; + public static explicit operator byte(DyAny value) => (byte)value.Ptr; + public static explicit operator sbyte(DyAny value) => (sbyte)value.Ptr; + public static explicit operator string(DyAny value) => (string)value.Ptr; + public static explicit operator char(DyAny value) => (char)value.Ptr; + public static explicit operator bool(DyAny value) => (bool)value.Ptr; + public static explicit operator double(DyAny value) => (double)value.Ptr; + public static explicit operator float(DyAny value) => (float)value.Ptr; + public static implicit operator Any(DyAny value) => value.Ptr; + + #endregion + + public override string ToString() => Ptr.ToString(); + + public override int GetHashCode() => Ptr.GetHashCode(); + } + + internal class JuliaDynamic : DynamicMetaObject + { + private static readonly MethodInfo FuncInvokeMi = typeof(Any).GetMethod("Invoke", new[] { typeof(DyAny), typeof(Any) }); + + private static readonly ConstructorInfo JuliaDyVci = typeof(DyAny).GetConstructor(new[] { typeof(Any) }); + + public JuliaDynamic(Expression expression, + DyAny any) : base(expression, BindingRestrictions.Empty, any) + { + } + + public override DynamicMetaObject BindGetMember(GetMemberBinder binder) + { + var expr = + Expression.New(JuliaDyVci, + Expression.Call(Expression.Constant(JPrimitive.getpropertyF), FuncInvokeMi, + Expression.Convert(Expression, typeof(DyAny)), + Expression.Constant(JuliaCalls.jl_symbol(binder.Name)))); + + var restr = BindingRestrictions.GetTypeRestriction(Expression, typeof(DyAny)); + return new DynamicMetaObject(expr, restr); + } + } +} diff --git a/Julia.NETstandard/src/Statics/ILCompiler/ILExprBuilder.cs b/Julia.NETstandard/src/Statics/ILCompiler/ILExprBuilder.cs new file mode 100644 index 0000000..7d362de --- /dev/null +++ b/Julia.NETstandard/src/Statics/ILCompiler/ILExprBuilder.cs @@ -0,0 +1,372 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using JuliaNET.Core; +using JuliaNET.Utils; + +namespace JuliaNET.Statics.ILCompiler +{ + public struct IlExprBuilder + { + private readonly ILGenerator _il; + public readonly object InternalMethod; + + public static implicit operator MethodBuilder(IlExprBuilder b) => (MethodBuilder)b.InternalMethod; + public static implicit operator ConstructorBuilder(IlExprBuilder b) => (ConstructorBuilder)b.InternalMethod; + + #region BuilderExtensions + + public struct ILFunctionExprBuilder + { + private readonly IlExprBuilder _eb; + + internal ILFunctionExprBuilder(IlExprBuilder eb) => _eb = eb; + + public void Invoke(string name, + params Type[] parameters) => + Invoke(SharpReflect.GetMethod(name, parameters)); + + public void Invoke(Type t, + string name, + params Type[] parameters) => + Invoke(SharpReflect.GetMethod(t, name, parameters)); + + public void Invoke(params Type[] parameters) => Invoke(SharpReflect.GetConstructor(parameters)); + + public void Invoke(Type t, + params Type[] parameters) => Invoke(SharpReflect.GetConstructor(t, parameters)); + + public void Invoke(MethodInfo info) => + _eb._il.EmitCall(info.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, info, null); + + public void Invoke(IlExprBuilder fb, + bool requiresConstructor = false, + bool requiresMethod = false) + { + if (fb.InternalMethod is MethodBuilder mb && !requiresConstructor) + Invoke(mb); + else if (fb.InternalMethod is ConstructorBuilder cb && !requiresMethod) + Invoke(cb); + else throw new Exception("Unable To Invoke Unknown Internal Method!"); + } + + public void Invoke(ConstructorInfo ci) => _eb._il.Emit(OpCodes.Newobj, ci); + + public void Println(string s) => _eb._il.EmitWriteLine(s); + } + + public struct ILLoadExprBuilder + { + private static readonly MethodInfo GET_RUNTIME_TYPE = typeof(Type).GetMethod("GetTypeFromHandle"); + + private readonly IlExprBuilder _eb; + internal ILLoadExprBuilder(IlExprBuilder eb) => _eb = eb; + + public void Arg(uint i) + { + if (i < 4) + { + if (i == 0) + _eb.Emit(OpCodes.Ldarg_0); + else if (i == 1) + _eb.Emit(OpCodes.Ldarg_1); + else if (i == 2) + _eb.Emit(OpCodes.Ldarg_2); + else _eb.Emit(OpCodes.Ldarg_3); + } + else if (i < 255) + _eb._il.Emit(OpCodes.Ldarg_S, i); + else + _eb._il.Emit(OpCodes.Ldarg, i); + } + + public void String(string str) => _eb._il.Emit(OpCodes.Ldstr, str); + public void Bool(bool b) => _eb._il.Emit(b ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + public void Int64(Int64 v) => _eb._il.Emit(OpCodes.Ldc_I8, v); + public void Int32(Int32 v) => _eb._il.Emit(OpCodes.Ldc_I4, v); + public void Int16(Int16 v) => Int32(v); + public void Int8(sbyte v) => Int32(v); + public void UInt64(UInt64 v) => _eb._il.Emit(OpCodes.Ldc_I8, v); + public void UInt32(UInt32 v) => _eb._il.Emit(OpCodes.Ldc_I4, v); + public void UInt16(UInt16 v) => UInt32(v); + public void UInt8(byte v) => UInt32(v); + public void Float32(float v) => _eb._il.Emit(OpCodes.Ldc_R4, v); + public void Float64(double v) => _eb._il.Emit(OpCodes.Ldc_R8, v); + + public void Type(Type t) + { + _eb._il.Emit(OpCodes.Ldtoken, t); + _eb.Function.Invoke(GET_RUNTIME_TYPE); + } + + public void FieldValue(FieldInfo f) => _eb._il.Emit(f.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, f); + public void FieldValue(FieldBuilder fb) => _eb._il.Emit(fb.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fb); + + public void FieldAddr(FieldInfo f) => _eb._il.Emit(f.IsStatic ? OpCodes.Ldsflda : OpCodes.Ldsfld, f); + public void FieldAddr(FieldBuilder fb) => _eb._il.Emit(fb.IsStatic ? OpCodes.Ldsflda : OpCodes.Ldsfld, fb); + + public void OptFloat(double v) + { + if (v > float.MaxValue) + Float32((float)v); + else + Float64(v); + } + + public void OptInt(Int64 v) + { + bool less = v < 0; + if (less) v *= -1; + if (v < System.Int32.MaxValue) + Int32((Int32)v * (less ? -1 : 1)); + else + Int64(v * (less ? -1 : 1)); + } + + public void OptUInt(UInt64 v) + { + if (v < System.Int32.MaxValue) + UInt32((UInt32)v); + else + UInt64(v); + } + + public void Const(UInt64 v) => OptUInt(v); + public void Const(Int64 v) => OptInt(v); + public void Const(double v) => OptFloat(v); + public void Const(string s) => String(s); + public void Const(bool b) => Bool(b); + public void Local(LocalBuilder lb) => _eb._il.Emit(OpCodes.Ldloc, lb); + + public void FromPointerInt8() => _eb.Emit(OpCodes.Ldind_I1); + public void FromPointerInt16() => _eb.Emit(OpCodes.Ldind_I2); + public void FromPointerInt32() => _eb.Emit(OpCodes.Ldind_I4); + public void FromPointerInt64() => _eb.Emit(OpCodes.Ldind_I8); + public void FromPointerFloat32() => _eb.Emit(OpCodes.Ldind_R4); + public void FromPointerFloat64() => _eb.Emit(OpCodes.Ldind_R8); + public void FromPointerRef() => _eb.Emit(OpCodes.Ldind_Ref); + + public void FromPointer(Type t) + { + if (t.IsPrimitive) + { + if (t == typeof(byte) || t == typeof(sbyte)) + FromPointerInt8(); + else if (t == typeof(Int16) || t == typeof(UInt16)) + FromPointerInt16(); + else if (t == typeof(Int32) || t == typeof(UInt32)) + FromPointerInt32(); + else if (t == typeof(Int64) || t == typeof(UInt64)) + FromPointerInt64(); + else if (t == typeof(float)) + FromPointerFloat32(); + else if (t == typeof(double)) + FromPointerFloat64(); + else throw new JuliaException("Unable to Determine Pointer Type T"); + } + else if (t.IsByRef) + { + FromPointerRef(); + } + else throw new JuliaException("Unable to Determine Pointer Type T"); + } + } + + public struct ILStoreExprBuilder + { + private readonly IlExprBuilder _eb; + internal ILStoreExprBuilder(IlExprBuilder eb) => _eb = eb; + + public void Field(FieldInfo f) => _eb._il.Emit(f.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, f); + public void Field(FieldBuilder fb) => _eb._il.Emit(fb.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fb); + + public void Local(LocalBuilder lb) => _eb._il.Emit(OpCodes.Stloc, lb); + + public void ToPointerInt8() => _eb.Emit(OpCodes.Stind_I1); + public void ToPointerInt16() => _eb.Emit(OpCodes.Stind_I2); + public void ToPointerInt32() => _eb.Emit(OpCodes.Stind_I4); + public void ToPointerInt64() => _eb.Emit(OpCodes.Stind_I8); + public void ToPointerFloat32() => _eb.Emit(OpCodes.Stind_R4); + public void ToPointerFloat64() => _eb.Emit(OpCodes.Stind_R8); + public void ToPointerRef() => _eb.Emit(OpCodes.Stind_Ref); + + public void ToPointer(Type t) + { + if (t.IsPrimitive) + { + if (t == typeof(byte) || t == typeof(sbyte)) + ToPointerInt8(); + else if (t == typeof(Int16) || t == typeof(UInt16)) + ToPointerInt16(); + else if (t == typeof(Int32) || t == typeof(UInt32)) + ToPointerInt32(); + else if (t == typeof(Int64) || t == typeof(UInt64)) + ToPointerInt64(); + else if (t == typeof(float)) + ToPointerFloat32(); + else if (t == typeof(double)) + ToPointerFloat64(); + else throw new JuliaException("Unable to Determine Pointer Type T"); + } + else if (t.IsByRef) + { + ToPointerRef(); + } + else throw new JuliaException("Unable to Determine Pointer Type T"); + } + } + + public struct ILCreateExprBuilder + { + private readonly IlExprBuilder _eb; + internal ILCreateExprBuilder(IlExprBuilder eb) => _eb = eb; + + public LocalBuilder Local(Type t, + bool pinned = false) => _eb._il.DeclareLocal(t, pinned); + + public LocalBuilder Local() => Local(typeof(T)); + + public LocalBuilder LocalAndStore(Type t) + { + var lb = Local(t); + _eb.Store.Local(lb); + return lb; + } + + public LocalBuilder LocalAndStore() => LocalAndStore(typeof(T)); + + public void Object(ConstructorInfo ci) => _eb.Function.Invoke(ci); + public void Object(IlExprBuilder cb) => _eb.Function.Invoke(cb, true); + public void Object(params Type[] parameters) => _eb.Function.Invoke(parameters); + + public void Object(Type t, + params Type[] parameters) => _eb.Function.Invoke(t, parameters); + } + + public struct ILArrayExprBuilder + { + private readonly IlExprBuilder _eb; + internal ILArrayExprBuilder(IlExprBuilder eb) => _eb = eb; + + public void LoadElement(int i, + Type t) + { + _eb.Load.Const(i); + LoadElement(t); + } + + public void LoadElement(int i) => LoadElement(i, typeof(T)); + + public void LoadElement(Type t) => _eb._il.Emit(OpCodes.Ldelem, t); + public void LoadElement() => LoadElement(typeof(T)); + + public void StoreElement(Type t) => _eb._il.Emit(OpCodes.Stelem, t); + public void StoreElement() => StoreElement(typeof(T)); + public void StoreElement(int i) => StoreElement(i, typeof(T)); + + public void LoadElementArrayAddress() => _eb._il.Emit(OpCodes.Ldelema); + + public void LoadElementArrayAddress(int i) + { + _eb.Load.Const(i); + LoadElementArrayAddress(); + } + + public void StoreElement(int i, + Type t) + { + _eb.Load.Const(i); + StoreElement(t); + } + + public void Create1d(Type elType) => _eb._il.Emit(OpCodes.Newarr, elType); + + public void Create1d(Type elType, + int size) + { + _eb.Load.Const(size); + Create1d(elType); + } + } + + public struct ILUnsafeExprBuilder + { + private readonly IlExprBuilder _eb; + internal ILUnsafeExprBuilder(IlExprBuilder eb) => _eb = eb; + + public void StackAlloc() => _eb._il.Emit(OpCodes.Localloc); + + public void StackAlloc(Type t, + int size) + { + _eb.Load.UInt32((uint)(Marshal.SizeOf(t) * size)); + StackAlloc(); + } + + public void StackAlloc(int size) => StackAlloc(typeof(T), size); + public void StoreToPointer(Type t) => _eb.Store.ToPointer(t); + public void StoreToPointer() => StoreToPointer(typeof(T)); + public void LoadFromPointer(Type t) => _eb.Load.FromPointer(t); + public void LoadFromPointer() => LoadFromPointer(typeof(T)); + + public void CopyBlock(int numBytes) + { + _eb.Load.Int32(numBytes); + CopyBlock(); + } + + public void CopyBlock() => _eb._il.Emit(OpCodes.Cpblk); + } + + #endregion + + #region BuilderExtensionImpl + + public ILFunctionExprBuilder Function => new(this); + public ILLoadExprBuilder Load => new(this); + public ILStoreExprBuilder Store => new(this); + public ILCreateExprBuilder Create => new(this); + public ILArrayExprBuilder Array => new(this); + public ILUnsafeExprBuilder Unsafe => new(this); + + #endregion + + private IlExprBuilder(ILGenerator il, + object internalMethod) + { + _il = il; + InternalMethod = internalMethod; + } + + public IlExprBuilder(MethodBuilder mb) : this(mb.GetILGenerator(), mb) { } + + public IlExprBuilder(ConstructorBuilder cb) : this(cb.GetILGenerator(), cb) { } + + #region HelperFunctions + + public void Emit(OpCode code) => _il.Emit(code); + + public void Return() => Emit(OpCodes.Ret); + public void Add() => Emit(OpCodes.Add); + public void Sub() => Emit(OpCodes.Sub); + public void Duplicate() => Emit(OpCodes.Dup); + public void Box(Type t) => _il.Emit(OpCodes.Box, t); + public void Box() => Box(typeof(T)); + + public void ReturnVoid() + { + _il.Emit(OpCodes.Nop); + Return(); + } + + public static IlExprBuilder CreateDynamicFunction(out DynamicMethod m, + string name = "") + { + m = new DynamicMethod(name, typeof(object), Type.EmptyTypes, typeof(string).Module); + return new(m.GetILGenerator(), m); + } + + #endregion + } +} diff --git a/Julia.NETstandard/src/Statics/ILCompiler/ILTypeBuilder.cs b/Julia.NETstandard/src/Statics/ILCompiler/ILTypeBuilder.cs new file mode 100644 index 0000000..aff00d4 --- /dev/null +++ b/Julia.NETstandard/src/Statics/ILCompiler/ILTypeBuilder.cs @@ -0,0 +1,91 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace JuliaNET.Statics.ILCompiler +{ + public struct ILTypeBuilder + { + public readonly TypeBuilder InternalBuilder; + public readonly IlExprBuilder TypeInitializer; + + internal ILTypeBuilder(TypeBuilder t) + { + TypeInitializer = new IlExprBuilder(t.DefineTypeInitializer()); + InternalBuilder = t; + } + + private FieldBuilder CreateFieldImpl(string name, + Type type, + FieldAttributes extra) => InternalBuilder.DefineField(name, type, extra); + + public FieldBuilder CreateField(string name, + Type type, + bool isConst, + bool isStatic = false, + FieldAttributes extraAttribs = FieldAttributes.Public) + { + FieldAttributes fa = extraAttribs; + if (isConst) + fa |= FieldAttributes.InitOnly; + if (isStatic) + fa |= FieldAttributes.Static; + return CreateFieldImpl(name, type, fa); + } + + public PropertyBuilder CreateProperty(string name, + Type t, + PropertyAttributes attribs = PropertyAttributes.None) => InternalBuilder.DefineProperty(name, attribs, t, Type.EmptyTypes); + + public IlExprBuilder CreateMethod(string name, + Type returnType, + params Type[] parameters) => CreateMethod(name, returnType, MethodAttributes.Static | MethodAttributes.Public, parameters); + + public IlExprBuilder CreateMethod(string name, + Type returnType, + MethodAttributes attributes, + params Type[] parameters) => new(InternalBuilder.DefineMethod(name, attributes, returnType, parameters)); + + public IlExprBuilder CreateGetMethod(PropertyBuilder pb) + { + var mb = CreateMethod("get_" + pb.Name, pb.PropertyType, MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName, Type.EmptyTypes); + pb.SetGetMethod(mb); + return mb; + } + + public IlExprBuilder CreateMethod(string name) => CreateMethod(name, typeof(void)); + public IlExprBuilder CreateMethod(string name) => CreateMethod(name, typeof(TOut)); + public IlExprBuilder CreateMethod(string name) => CreateMethod(name, typeof(TOut), typeof(T1)); + public IlExprBuilder CreateMethod(string name) => CreateMethod(name, typeof(TOut), typeof(T1), typeof(T2)); + public IlExprBuilder CreateMethod(string name) => CreateMethod(name, typeof(TOut), typeof(T1), typeof(T2), typeof(T3)); + public IlExprBuilder CreateMethod(string name) => CreateMethod(name, typeof(TOut), typeof(T1), typeof(T2), typeof(T3), typeof(T4)); + public IlExprBuilder CreateMethod(string name) => CreateMethod(name, typeof(TOut), typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5)); + + public IlExprBuilder CreateConstructor(params Type[] parameters) => + new(InternalBuilder.DefineConstructor(MethodAttributes.Static | MethodAttributes.Public, + CallingConventions.Any, parameters)); + + public IlExprBuilder CreateConstructor() => CreateConstructor(typeof(T1)); + public IlExprBuilder CreateConstructor() => CreateConstructor(typeof(T1), typeof(T2)); + public IlExprBuilder CreateConstructor() => CreateConstructor(typeof(T1), typeof(T2), typeof(T3)); + public IlExprBuilder CreateConstructor() => CreateConstructor(typeof(T1), typeof(T2), typeof(T3), typeof(T4)); + public IlExprBuilder CreateConstructor() => CreateConstructor(typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5)); + + public Type Create() + { + var ti = TypeInitializer; + ti.ReturnVoid(); + return InternalBuilder.CreateTypeInfo(); + } + + public static bool IsAllowedName(string s) + { + if (!(char.IsLetter(s[0]) || s[0] == '_')) + return false; + foreach (var c in s) + if (!(char.IsLetterOrDigit(c) || char.IsSeparator(c))) + return false; + return true; + } + } +} diff --git a/Julia.NETstandard/src/Statics/ILCompiler/ILUtils.cs b/Julia.NETstandard/src/Statics/ILCompiler/ILUtils.cs new file mode 100644 index 0000000..8f92b52 --- /dev/null +++ b/Julia.NETstandard/src/Statics/ILCompiler/ILUtils.cs @@ -0,0 +1,6 @@ +namespace JuliaNET.Statics.ILCompiler +{ + public class ILUtils + { + } +} diff --git a/Julia.NETstandard/src/Statics/JuliaAttributes.cs b/Julia.NETstandard/src/Statics/JuliaAttributes.cs new file mode 100644 index 0000000..86f8047 --- /dev/null +++ b/Julia.NETstandard/src/Statics/JuliaAttributes.cs @@ -0,0 +1,40 @@ +using System; +using System.Reflection; + +namespace JuliaNET.Statics +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class JModuleAttribute : Attribute + { + internal static readonly ConstructorInfo DEF_CON = typeof(JModuleAttribute).GetConstructor(Type.EmptyTypes); + public JModuleAttribute() { } + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class JStructAttribute : Attribute + { + internal static readonly ConstructorInfo DEF_CON = typeof(JStructAttribute).GetConstructor(Type.EmptyTypes); + public JStructAttribute() { } + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class JMutableStructAttribute : Attribute + { + internal static readonly ConstructorInfo DEF_CON = typeof(JMutableStructAttribute).GetConstructor(Type.EmptyTypes); + public JMutableStructAttribute() { } + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class JAbstractTypeAttribute : Attribute + { + internal static readonly ConstructorInfo DEF_CON = typeof(JAbstractTypeAttribute).GetConstructor(Type.EmptyTypes); + public JAbstractTypeAttribute() { } + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class JPrimitiveAttribute : Attribute + { + internal static readonly ConstructorInfo DEF_CON = typeof(JPrimitiveAttribute).GetConstructor(Type.EmptyTypes); + public JPrimitiveAttribute() { } + } +} diff --git a/Julia.NETstandard/src/Statics/JuliaStaticFunction.cs b/Julia.NETstandard/src/Statics/JuliaStaticFunction.cs new file mode 100644 index 0000000..73eac18 --- /dev/null +++ b/Julia.NETstandard/src/Statics/JuliaStaticFunction.cs @@ -0,0 +1,13 @@ +using JuliaNET.Stdlib; + +namespace JuliaNET.Statics +{ + public partial class JuliaStaticLibrary + { + private void GenerateFunction(JuliaStaticModule mod, + Any name, + Any value) + { + } + } +} diff --git a/Julia.NETstandard/src/Statics/JuliaStaticLibrary.cs b/Julia.NETstandard/src/Statics/JuliaStaticLibrary.cs new file mode 100644 index 0000000..129c509 --- /dev/null +++ b/Julia.NETstandard/src/Statics/JuliaStaticLibrary.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using JuliaNET.Core; +using JuliaNET.Statics.ILCompiler; +using JuliaNET.Stdlib; +using JuliaNET.Utils; +using Lokad.ILPack; + +namespace JuliaNET.Statics +{ + public partial class JuliaStaticLibrary + { + private readonly Any _baseModule; + + private ModuleBuilder _baseModuleBuilder; + + private ILTypeBuilder _baseModuleTypeBuilder; + + private FieldInfo UniversalConstantsFI; + + private readonly Dictionary _universalConstants = new(); + + private static readonly MethodInfo JuliaEvalMI = + SharpReflect.GetMethod("Eval"); + + private static readonly FieldInfo WriteSharpEvalMI = + SharpReflect.GetField(typeof(JPrimitive), "writeSharpArrayF"); + + private static readonly MethodInfo jl_call_2mi = typeof(JuliaCalls).GetMethod("jl_call2"); + + public JuliaStaticLibrary(Any module) => _baseModule = module; + + public void Generate(string libPath) + { + var modName = _baseModule.ToString(); + var asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(modName), AssemblyBuilderAccess.Run); + _baseModuleBuilder = asm.DefineDynamicModule(modName); + _baseModuleTypeBuilder = new ILTypeBuilder(_baseModuleBuilder.DefineType("jl." + ConvertJuliaName(modName), + TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed)); + var mb = GenerateModule(new(_baseModule, _baseModuleTypeBuilder, null), true); + WriteUniversalConstants(mb); + mb.Create(); + new AssemblyGenerator().GenerateAssembly(asm, libPath); + } + + private void WriteUniversalConstants(ILTypeBuilder mb) + { + if (UniversalConstantsFI == null) + return; + + StringBuilder sb = new("["); + var keys = _universalConstants.Keys.GetEnumerator(); + keys.MoveNext(); + sb.Append(keys.Current); + while (keys.MoveNext()) + sb.Append(',').Append(keys.Current); + sb.Append("]"); + keys.Dispose(); + + var mi = mb.TypeInitializer; + var ptr = mi.Create.Local(typeof(Any*), true); + /* CONSTANTS = new Any[len]; + fixed(Any* ptr = CONSTANTS){ + Julia.Eval("[:sym1, ...]") + }*/ + mi.Array.Create1d(typeof(Any), _universalConstants.Count); + mi.Store.Field(UniversalConstantsFI); + mi.Load.FieldValue(UniversalConstantsFI); + mi.Store.Local(ptr); + // mi.Array.LoadElementArrayAddress(0); + mi.Load.Local(ptr); + mi.Load.Const(sb.ToString()); + mi.Function.Invoke(JuliaEvalMI); + mi.Function.Invoke(jl_call_2mi); + } + + private static void DecorateWithDefAttribute(TypeBuilder tb, + ConstructorInfo ci) + { + CustomAttributeBuilder cab = new(ci, Array.Empty()); + tb.SetCustomAttribute(cab); + } + + private void LoadUniversalConstant(IlExprBuilder eb, + int idx) + { + UniversalConstantsFI ??= _baseModuleTypeBuilder.CreateField(ConvertJuliaName("CONSTANTS"), typeof(Any[]), true, true); + eb.Load.FieldValue(UniversalConstantsFI); + eb.Array.LoadElement(idx); + } + + private void LoadUniversalConstant(IlExprBuilder eb, + string symbol) + { + if (_universalConstants.TryGetValue(symbol, out var v)) + { + LoadUniversalConstant(eb, v); + return; + } + + var cnt = _universalConstants.Count; + _universalConstants.Add(symbol, cnt); + LoadUniversalConstant(eb, cnt); + } + + private void LoadSymbol(IlExprBuilder eb, + string symbol) => LoadUniversalConstant(eb, ":" + symbol); + + private bool ConvertJuliaName(string s, + out string v) + { + if (ILTypeBuilder.IsAllowedName(s)) + { + v = s; + return true; + } + + v = s.Replace('!', '_'); + if (ILTypeBuilder.IsAllowedName(v)) + return true; + + v = null; + return false; + } + + private string ConvertJuliaName(string s) + { + if (ConvertJuliaName(s, out var v)) + return s; + throw new Exception("Unable to convert Julia Name:" + s); + } + } +} diff --git a/Julia.NETstandard/src/Statics/JuliaStaticModule.cs b/Julia.NETstandard/src/Statics/JuliaStaticModule.cs new file mode 100644 index 0000000..e211778 --- /dev/null +++ b/Julia.NETstandard/src/Statics/JuliaStaticModule.cs @@ -0,0 +1,95 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; +using JuliaNET.Core; +using JuliaNET.Statics.ILCompiler; +using JuliaNET.Stdlib; +using JuliaNET.Utils; + +namespace JuliaNET.Statics +{ + internal class JuliaStaticModule + { + public Any Module; + public ILTypeBuilder ModuleBuilder; + public readonly FieldBuilder JModuleField, JParentModule, ParentModuleTy; + private static readonly FieldInfo MainModuleField = SharpReflect.GetField(typeof(JPrimitive), "MainM"); + + public JuliaStaticModule(Any module, + ILTypeBuilder moduleBuilder, + FieldBuilder parentModuleField) + { + var ti = moduleBuilder.TypeInitializer; + Module = module; + ModuleBuilder = moduleBuilder; + JModuleField = moduleBuilder.CreateField("Module", typeof(Any), true, true); + JParentModule = moduleBuilder.CreateField("ParentModule", typeof(Any), true, true); + ParentModuleTy = moduleBuilder.CreateField("ParentModuleType", typeof(Type), true, true); + + if (parentModuleField != null) + { + //ParentModule = ParentModuleType.Module; + //ParentModuleTy = typeof(ParentModuleType); + ti.Load.FieldValue(parentModuleField); + ti.Load.Type(parentModuleField.DeclaringType); + } + else + { + //ParentModule = JPrimitive.MainM; + //ParentModuleTy = typeof(thistype); + ti.Load.FieldValue(MainModuleField); + ti.Load.Type(MainModuleField.DeclaringType); + } + + ti.Store.Field(ParentModuleTy); + ti.Store.Field(JParentModule); + + // ti.Load.Const(module.ToString()); + // ti.Function.Invoke(getglobalstr); + // ti.Store.Field(JModuleField); + } + } + + public partial class JuliaStaticLibrary + { + private ILTypeBuilder GenerateModule(JuliaStaticModule mod, + bool isFirst) + { + try + { + DecorateWithDefAttribute(mod.ModuleBuilder.InternalBuilder, JModuleAttribute.DEF_CON); + + foreach (var name in JPrimitive.namesF.Invoke(mod.Module)) + { + if (JuliaCalls.jl_is_const(mod.Module, name) != 0) + { + var val = Core.Julia.GetGlobal(mod.Module, name); + if (val.Is(JPrimitive.FunctionT)) + GenerateFunction(mod, name, val); + else if (val.Is(JPrimitive.ModuleT) && val != mod.Module) + { + var mb = mod.ModuleBuilder.InternalBuilder.DefineNestedType(ConvertJuliaName(name.ToString()), + TypeAttributes.Class | TypeAttributes.NestedPublic | TypeAttributes.Abstract | TypeAttributes.Sealed); + GenerateModule(new(val, new(mb), mod.JModuleField), false); + } + else if (val.Is(JPrimitive.TypeT) && IsNETRepresentable(val)) + GenerateType(mod, name, val); + else + GenerateVar(mod, name, true); + } + else + GenerateVar(mod, name, false); + } + + if (!isFirst) + mod.ModuleBuilder.Create(); + return mod.ModuleBuilder; + } + catch (Exception) + { + Console.WriteLine("Caught Error While Generating Module:" + mod.Module); + throw; + } + } + } +} diff --git a/Julia.NETstandard/src/Statics/JuliaStaticType.cs b/Julia.NETstandard/src/Statics/JuliaStaticType.cs new file mode 100644 index 0000000..60c9774 --- /dev/null +++ b/Julia.NETstandard/src/Statics/JuliaStaticType.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using JuliaNET.Core; +using JuliaNET.Stdlib; +using JuliaNET.Utils; + +namespace JuliaNET.Statics +{ + public partial class JuliaStaticLibrary + { + private void GenerateType(JuliaStaticModule mod, + Any name, + JType type) + { + try + { + var mb = mod.ModuleBuilder; + var typename = name.ToString(); + if (mb.InternalBuilder.Module.GetType(typename) != null) return; + var typetype = type.Type; + TypeBuilder tb; + + switch (typetype) + { + case JTypeType.MutableStruct: + int field_count = type.FieldCount; + tb = mb.InternalBuilder.DefineNestedType(typename, + TypeAttributes.NestedPublic | TypeAttributes.Class); + DecorateWithDefAttribute(tb, JMutableStructAttribute.DEF_CON); + for (int i = 0; i < field_count; i++) + { + type.FieldType(i).Name.Println(); + var fb = tb.DefineField(type.FieldName(i), + mb.InternalBuilder.Module.GetType(type.FieldType(i).Name), FieldAttributes.Public); + } + + break; + case JTypeType.Abstract: + tb = mb.InternalBuilder.DefineNestedType(typename, + TypeAttributes.NestedPublic | TypeAttributes.Abstract); + DecorateWithDefAttribute(tb, JAbstractTypeAttribute.DEF_CON); + break; + case JTypeType.Primitive: + tb = mb.InternalBuilder.DefineNestedType(typename, + TypeAttributes.NestedPublic | TypeAttributes.SequentialLayout, + typeof(ValueType), type.SizeOf); + DecorateWithDefAttribute(tb, JPrimitiveAttribute.DEF_CON); + break; + default: + int fieldcount = type.FieldCount; + tb = mb.InternalBuilder.DefineNestedType(typename, + TypeAttributes.NestedPublic | TypeAttributes.SequentialLayout, + typeof(ValueType)); + DecorateWithDefAttribute(tb, JStructAttribute.DEF_CON); + break; + } + } + catch (Exception) + { + Console.WriteLine("Caught Error While Generating Type:" + type + " (" + type.Type + ")"); + throw; + } + } + + private bool IsNETRepresentable(JType t) + { + return false; + } + + private bool ResolveLocalType(JuliaStaticModule mod, + JType ty, + out Type t) + { + List modules = new(); + var w = ty.Module; + while (w != w.Parent) + { + modules.Add(w); + w = w.Parent; + } + + if (modules.Count > 0) + { + var tb = (TypeBuilder)_baseModuleBuilder.GetType(modules[modules.Count - 1].ToString()); + for (int i = modules.Count - 2; i > -1; i--) + tb = (TypeBuilder)tb.GetNestedType(modules[i].ToString()); + t = tb.GetNestedType(ty.Name); + } + else t = _baseModuleBuilder.GetType(ty.Name); + + return true; + } + + private Type ResolveType(JuliaStaticModule mod, + Any shortName) + { + var jty = JPrimitive.getpropertyF.Invoke(mod.Module, shortName).Type; + try + { + if (IsNETRepresentable(jty)) + { + if (ResolveLocalType(mod, jty, out var t)) + return t; + throw new Exception("Unable To Resolve Type:" + jty); + } + + return typeof(Any); + } + catch (Exception) + { + Console.WriteLine("Caught Error While Resolving Type:" + jty); + throw; + } + } + } +} diff --git a/Julia.NETstandard/src/Statics/JuliaStaticVar.cs b/Julia.NETstandard/src/Statics/JuliaStaticVar.cs new file mode 100644 index 0000000..e286cbe --- /dev/null +++ b/Julia.NETstandard/src/Statics/JuliaStaticVar.cs @@ -0,0 +1,49 @@ +using System; +using System.Reflection; +using JuliaNET.Stdlib; +using JuliaNET.Utils; + +namespace JuliaNET.Statics +{ + public partial class JuliaStaticLibrary + { + internal static readonly MethodInfo + getglobalsym = SharpReflect.GetMethod("GetGlobal"), + getglobalstr = SharpReflect.GetMethod("GetGlobal"); + + private void GenerateVar(JuliaStaticModule mod, + Any name, + bool constant) + { + try + { + var varname = name.ToString(); + var ty = ResolveType(mod, name); + + //Throw away names we cant represent as they probably are internal + if (!ConvertJuliaName(varname, out var netName)) + return; + + var pb = mod.ModuleBuilder.CreateProperty(netName, ty); + var mb = mod.ModuleBuilder.CreateGetMethod(pb); + + if (constant) + LoadUniversalConstant(mb, varname); + else + { + //Module.varname => Julia.GetGlobal(Module.Module, :varname) + mb.Load.FieldValue(mod.JModuleField); + LoadSymbol(mb, varname); + mb.Function.Invoke(getglobalsym); + } + + mb.Return(); + } + catch (Exception) + { + Console.WriteLine("Caught Error While Generating Constant:" + name); + throw; + } + } + } +} diff --git a/Julia.NETstandard/src/Stdlib/Any.cs b/Julia.NETstandard/src/Stdlib/Any.cs new file mode 100644 index 0000000..20fc3fd --- /dev/null +++ b/Julia.NETstandard/src/Stdlib/Any.cs @@ -0,0 +1,523 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using JuliaNET.Core; +using JuliaNET.Dynamics; +using JuliaNET.Utils; + +namespace JuliaNET.Stdlib +{ + [StructLayout(LayoutKind.Sequential)] + public struct Any : IDynamicMetaObjectProvider, JEnumerable, JVal + { + private readonly IntPtr ptr; + Any JVal.This => this; + + public Any(IntPtr ptr) => this.ptr = ptr; + + public bool IsEnumerable => !this.Type.IsPrimitive; + + #region Conversion + + public unsafe Any(void* l) : this(JuliaCalls.jl_box_voidpointer(new IntPtr(l))) + { + } + + public Any(long l) : this(JuliaCalls.jl_box_int64(l)) + { + } + + public Any(int l) : this(JuliaCalls.jl_box_int32(l)) + { + } + + public Any(short l) : this(JuliaCalls.jl_box_int16(l)) + { + } + + public Any(sbyte l) : this(JuliaCalls.jl_box_int8(l)) + { + } + + public Any(ulong l) : this(JuliaCalls.jl_box_uint64(l)) + { + } + + public Any(uint l) : this(JuliaCalls.jl_box_uint32(l)) + { + } + + public Any(ushort l) : this(JuliaCalls.jl_box_uint16(l)) + { + } + + public Any(byte l) : this(JuliaCalls.jl_box_uint8(l)) + { + } + + public Any(char l) : this(JuliaCalls.jl_box_int32(l)) + { + } + + public Any(bool l) : this(JuliaCalls.jl_box_bool(l)) + { + } + + public Any(double l) : this(JuliaCalls.jl_box_float64(l)) + { + } + + public Any(float l) : this(JuliaCalls.jl_box_float32(l)) + { + } + + // public Any(Half l) : this(JuliaCalls.jl_box_float32((float)l)) + // { + // } + + public Any(string s) : this(JuliaCalls.jl_cstr_to_string(s)) + { + } + + public Any(Array a) : this(new JArray(a)) + { + } + + public Any(Array a, + bool own) : this(new JArray(a, own)) + { + } + + public Any(object o) : this(CreateFromObject(o)) { } + + private static Any CreateFromObject(object o) + { + if (o.GetType().IsPrimitive) + switch (o) + { + case bool i: return i; + case char i: return i; + + case sbyte i: return i; + case short i: return i; + case int i: return i; + case long i: return i; + + case byte i: return i; + case ushort i: return i; + case uint i: return i; + case ulong i: return i; + + // case Half i: return i; + case float i: return i; + case double i: return i; + } + else if (o is string s) + return s; + else if (o is Array a) + return new(a); + else if (o is IntPtr i) + return i; + + throw new Exception("Unable To Box:" + o + " To Julia"); + } + + public static implicit operator IntPtr(Any value) => value.ptr; + public static implicit operator Any(IntPtr ptr) => new Any(ptr); + public static implicit operator Any(long l) => new Any(l); + public static implicit operator Any(ulong l) => new Any(l); + public static implicit operator Any(int l) => new(l); + public static implicit operator Any(uint l) => new Any(l); + public static implicit operator Any(short l) => new Any(l); + public static implicit operator Any(ushort l) => new Any(l); + public static implicit operator Any(string l) => new Any(l); + public static implicit operator Any(double l) => new Any(l); + + public static implicit operator Any(float l) => new Any(l); + + // public static implicit operator Any(Half l) => new Any(l); + public static implicit operator Any(char l) => new Any(l); + public static implicit operator Any(bool l) => new Any(l); + public static implicit operator Any(byte l) => new Any(l); + public static implicit operator Any(sbyte l) => new Any(l); + + public static explicit operator long(Any value) => value.UnboxInt64(); + public static explicit operator ulong(Any value) => value.UnboxUInt64(); + public static explicit operator int(Any value) => value.UnboxInt32(); + public static explicit operator uint(Any value) => value.UnboxUInt32(); + public static explicit operator short(Any value) => value.UnboxInt16(); + public static explicit operator ushort(Any value) => value.UnboxUInt16(); + public static explicit operator byte(Any value) => value.UnboxUInt8(); + public static explicit operator sbyte(Any value) => value.UnboxInt8(); + public static explicit operator string(Any value) => value.UnboxString(); + public static explicit operator char(Any value) => value.UnboxChar(); + public static explicit operator bool(Any value) => value.UnboxBool(); + public static explicit operator double(Any value) => value.UnboxFloat64(); + + public static explicit operator float(Any value) => value.UnboxFloat32(); + + // public static explicit operator Half(Any value) => value.UnboxFloat16(); + public long UnboxInt64() => JuliaCalls.jl_unbox_int64(this); + public int UnboxInt32() => JuliaCalls.jl_unbox_int32(this); + public short UnboxInt16() => JuliaCalls.jl_unbox_int16(this); + public sbyte UnboxInt8() => JuliaCalls.jl_unbox_int8(this); + public bool UnboxBool() => JuliaCalls.jl_unbox_bool(this); + public ulong UnboxUInt64() => JuliaCalls.jl_unbox_uint64(this); + public uint UnboxUInt32() => JuliaCalls.jl_unbox_uint32(this); + public ushort UnboxUInt16() => JuliaCalls.jl_unbox_uint16(this); + public byte UnboxUInt8() => JuliaCalls.jl_unbox_uint8(this); + public double UnboxFloat64() => JuliaCalls.jl_unbox_float64(this); + + public float UnboxFloat32() => JuliaCalls.jl_unbox_float32(this); + + // public Half UnboxFloat16() => (Half)JuliaCalls.jl_unbox_float32(this); + public char UnboxChar() => (char)JuliaCalls.jl_unbox_int32(this); + public IntPtr UnboxPtr() => JuliaCalls.jl_unbox_voidpointer(this); + public string UnboxString() => Core.Julia.UnboxString(this); + + public object UnboxObject(bool throwOnError = false) + { + if (Is(JPrimitive.IntegerT)) + switch (this.SizeOf) + { + case 1: return Is(JPrimitive.Int8T) ? (sbyte)this : (byte)this; + case 2: return Is(JPrimitive.Int16T) ? (short)this : (ushort)this; + case 4: return Is(JPrimitive.Int32T) ? (int)this : (uint)this; + case 8: return Is(JPrimitive.Int64T) ? (long)this : (ulong)this; + } + else if (Is(JPrimitive.AbstractFloatT)) + switch (this.SizeOf) + { + // case 2: return (Half)this; + case 4: return (float)this; + case 8: return (double)this; + } + else if (Is(JPrimitive.BoolT)) + return (bool)this; + else if (Is(JPrimitive.CharT)) + return (char)this; + else if (Is(JPrimitive.PtrT)) + return UnboxPtr(); + else if (Is(JPrimitive.StringT)) + return (string)this; + else if (Is(JPrimitive.ArrayT)) + return (JArray)this; + + if (throwOnError) + throw new Exception("Unable To Unbox Object " + this); + + return null; + } + + #endregion + + #region Invokation + + public Any Invoke() + { + var val = UnsafeInvoke(); + Core.Julia.CheckExceptions(); + return val; + } + + public Any Invoke(Any arg1) + { + var val = UnsafeInvoke(arg1); + Core.Julia.CheckExceptions(); + return val; + } + + public Any Invoke1(Any arg1) + { + var val = UnsafeInvoke(arg1); + Core.Julia.CheckExceptions(); + return val; + } + + public Any Invoke(DyAny arg1, + Any arg2) => Invoke(arg1.Ptr, arg2); + + public Any Invoke(Any arg1, + Any arg2) + { + Any val = UnsafeInvoke(arg1, arg2); + Core.Julia.CheckExceptions(); + return val; + } + + public Any Invoke(Any arg1, + Any arg2, + Any arg3) + { + var val = UnsafeInvoke(arg1, arg2, arg3); + Core.Julia.CheckExceptions(); + return val; + } + + public Any Invoke(params Any[] args) + { + var val = UnsafeInvoke(args); + Core.Julia.CheckExceptions(); + return val; + } + + // public Any InvokeSplat(params Any[] args) + // { + // var val = UnsafeInvokeSplat(args); + // Core.Julia.CheckExceptions(); + // return val; + // } + // + // public Any Invoke(Span args) + // { + // var val = UnsafeInvoke(args); + // Core.Julia.CheckExceptions(); + // return val; + // } + // + // public Any InvokeSplat(Span args) + // { + // var val = UnsafeInvokeSplat(args); + // Core.Julia.CheckExceptions(); + // return val; + // } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Any UnsafeInvoke() => JuliaCalls.jl_call0(this); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Any UnsafeInvoke(Any arg1) => JuliaCalls.jl_call1(this, arg1); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Any UnsafeInvoke1(Any arg1) => JuliaCalls.jl_call1(this, arg1); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Any UnsafeInvoke(Any arg1, + Any arg2) => JuliaCalls.jl_call2(this, arg1, arg2); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Any UnsafeInvoke(Any arg1, + Any arg2, + Any arg3) => + JuliaCalls.jl_call3(this, arg1, arg2, arg3); + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public unsafe Any UnsafeInvoke(Span args) => UnsafeInvoke(args.ToPointer(), args.Length); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe Any UnsafeInvoke(Any[] args) => UnsafeInvoke(args.ToPointer(), args.Length); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe Any UnsafeInvoke(Any* args, + int length) => JuliaCalls.jl_call(this, args, length); + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public unsafe Any UnsafeInvokeSplat(params Any[] args) => + // UnsafeInvokeSplat((Any*)Unsafe.AsPointer(ref args.GetPinnableReference()), args.Length); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe Any UnsafeInvokeSplat(Any* v, + int length) => JuliaCalls.jl_call(this, v, length); + + #endregion + + #region Array + + public Any this[Any idx] + { + get => JPrimitive.getindexF.UnsafeInvoke(ptr, idx); + set => JPrimitive.setindexNotF.UnsafeInvoke(ptr, idx, value); + } + + public Any this[Any i1, + Any i2] + { + get => JPrimitive.getindexF.UnsafeInvoke(ptr, i1, i2); + set => JPrimitive.setindexNotF.UnsafeInvoke(new Any[] { ptr, value, i1, i2 }); + } + + public Any this[Any i1, + Any i2, + Any i3] + { + get => JPrimitive.getindexF.UnsafeInvoke(new Any[] { ptr, i1, i2, i3 }); + set => JPrimitive.setindexNotF.UnsafeInvoke(new Any[] { ptr, value, i1, i2, i3 }); + } + + public Any this[Any i1, + Any i2, + Any i3, + Any i4] + { + get => JPrimitive.getindexF.UnsafeInvoke(new Any[] { ptr, i1, i2, i3, i4 }); + set => JPrimitive.setindexNotF.UnsafeInvoke(new Any[] { ptr, value, i1, i2, i3, i4 }); + } + + public unsafe Any this[Any[] args] + { + get + { + var a = stackalloc Any[args.Length + 1]; + a[0] = ptr; + Buffer.MemoryCopy(args.ToPointer(), a + 1, args.Length, args.Length); + return JPrimitive.getindexF.UnsafeInvoke(a, args.Length); + } + + set + { + var a = stackalloc Any[args.Length + 2]; + a[0] = ptr; + a[1] = value; + Buffer.MemoryCopy(args.ToPointer(), a + 2, args.Length, args.Length); + JPrimitive.setindexNotF.UnsafeInvoke(a, args.Length); + } + } + + #endregion + + #region UsefulFunctions + + public Any Module => JPrimitive.parentmoduleF.Invoke(this); + public int Length => (int)JPrimitive.lengthF.UnsafeInvoke(this); + public int SizeOf => (int)JPrimitive.sizeofF.Invoke(this); + public JType Type => JPrimitive.typeofF.Invoke(this); + public bool Is(JType ty) => Core.Julia.Isa(this, ty); + + public static string operator +(string s, + Any v) => s + v.ToString(); + + public static string operator +(Any v, + string s) => v.ToString() + s; + + #endregion + + #region Comparison + + public static bool operator ==(Any v, + IntPtr p) => v.ptr == p; + + public static bool operator !=(Any v, + IntPtr p) => v.ptr != p; + + public static bool operator ==(IntPtr p, + Any v) => v.ptr == p; + + public static bool operator !=(IntPtr p, + Any v) => v.ptr != p; + + public static bool operator ==(Any v, + Any v2) => (bool)JPrimitive.EqualityF.Invoke(v, v2); + + public static bool operator !=(Any v, + Any v2) => (bool)JPrimitive.InequalityF.Invoke(v, v2); + + public static bool operator >(Any v, + Any v2) => (bool)JPrimitive.GreaterThanF.Invoke(v, v2); + + public static bool operator <(Any v, + Any v2) => (bool)JPrimitive.LessThanF.Invoke(v, v2); + + public static bool operator >=(Any v, + Any v2) => (bool)JPrimitive.GreaterThanOrEqualF.Invoke(v, v2); + + public static bool operator <=(Any v, + Any v2) => (bool)JPrimitive.LessThanOrEqualF.Invoke(v, v2); + + public static Any operator !(Any v) => (bool)JPrimitive.NotF.Invoke(v); + + #endregion + + #region Math + + public static Any operator ~(Any v) => JPrimitive.OnesComplementF.Invoke(v); + + public static Any operator ^(Any v, + Any v2) => JPrimitive.ExclusiveOrF.Invoke(v, v2); + + public static Any operator &(Any v, + Any v2) => JPrimitive.BitwiseAndF.Invoke(v, v2); + + public static Any operator |(Any v, + Any v2) => JPrimitive.BitwiseOrF.Invoke(v, v2); + + public static Any operator %(Any v, + Any v2) => JPrimitive.ModulusF.Invoke(v, v2); + + public static Any operator *(Any v, + Any v2) => JPrimitive.MultiplyF.Invoke(v, v2); + + public static Any operator +(Any v, + Any v2) => JPrimitive.AdditionF.Invoke(v, v2); + + public static Any operator -(Any v, + Any v2) => JPrimitive.SubtractionF.Invoke(v, v2); + + public static Any operator /(Any v, + Any v2) => JPrimitive.DivisionF.Invoke(v, v2); + + public static Any operator >> (Any v, + int n) => JPrimitive.RightShiftF.Invoke(v, n); + + public static Any operator <<(Any v, + int n) => JPrimitive.LeftShiftF.Invoke(v, n); + + #endregion + + #region Enumerable + + void JEnumerable.EnumerationReset(Any s, + out Any ns) => ns = IntPtr.Zero; + + Any JEnumerable.EnumerationCurrent(Any s) => s[1]; + + void JEnumerable.EnumerationDispose() + { + } + + bool JEnumerable.EnumerationMoveNext(Any s, + out Any ns) + { + ns = s == IntPtr.Zero ? JPrimitive.iterateF.Invoke(this) : JPrimitive.iterateF.Invoke(this, s[2]); + return ns[2] != IntPtr.Zero; + } + + Any JEnumerable.EnumerationIndex(Any s) => s[2]; + + #endregion + + #region Builtin + + public override string ToString() => + ptr == IntPtr.Zero ? "null" : JPrimitive.stringF.Invoke1(this).UnboxString(); + + public override int GetHashCode() => (int)JPrimitive.hashF.Invoke1(this); + public DynamicMetaObject GetMetaObject(Expression parameter) => new JuliaDynamic(parameter, new(this)); + + #endregion + + #region Enumerator + + IEnumerator IEnumerable.GetEnumerator() + { + if (this.IsEnumerable) + return GetEnumerator(); + // can be a basic type, or an enumerable + // To prevent endless loop, we should not return a JEnumerator. + return (new [] { this }).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => + new JEnumerator(((JVal)this).This); + + private IEnumerator GetEnumerator() + { + return new JEnumerator(((JVal)this).This); + } + + #endregion + } +} diff --git a/Julia.NETstandard/src/Utils/CopyBlockHelper.cs b/Julia.NETstandard/src/Utils/CopyBlockHelper.cs new file mode 100644 index 0000000..d95524e --- /dev/null +++ b/Julia.NETstandard/src/Utils/CopyBlockHelper.cs @@ -0,0 +1,64 @@ +using System; +using System.Reflection.Emit; + +namespace JuliaNET.Utils; + +internal static class CopyBlockHelper +{ + // https://stackoverflow.com/a/51450057 + + internal static unsafe void SmartCopy(T* pointerDataOutCurrent, + T* pointerDataIn, + int length) where T : unmanaged + { + var sizeOfType = sizeof(T); + + var numberOfBytesInBlock = Convert.ToUInt32(sizeOfType * length); + + var numOfIterations = numberOfBytesInBlock / BlockSize; + var overheadOfLastIteration = numberOfBytesInBlock % BlockSize; + + uint offset; + for (var idx = 0u; idx < numOfIterations; idx++) + { + offset = idx * BlockSize; + CopyBlock(pointerDataOutCurrent + offset / sizeOfType, pointerDataIn + offset / sizeOfType, BlockSize); + } + + offset = numOfIterations * BlockSize; + CopyBlock(pointerDataOutCurrent + offset / sizeOfType, pointerDataIn + offset / sizeOfType, overheadOfLastIteration); + } + + private const int BlockSize = 16384; + + private static readonly CopyBlockDelegate CpBlock = GenerateCopyBlock(); + + private unsafe delegate void CopyBlockDelegate(void* des, + void* src, + uint bytes); + + private static unsafe void CopyBlock(void* dest, + void* src, + uint count) + { + var local = CpBlock; + local(dest, src, count); + } + + private static CopyBlockDelegate GenerateCopyBlock() + { + // Don't ask... + var method = new DynamicMethod("CopyBlockIL", typeof(void), + new[] { typeof(void*), typeof(void*), typeof(uint) }, typeof(CopyBlockHelper)); + var emitter = method.GetILGenerator(); + // emit IL + emitter.Emit(OpCodes.Ldarg_0); + emitter.Emit(OpCodes.Ldarg_1); + emitter.Emit(OpCodes.Ldarg_2); + emitter.Emit(OpCodes.Cpblk); + emitter.Emit(OpCodes.Ret); + + // compile to delegate + return (CopyBlockDelegate)method.CreateDelegate(typeof(CopyBlockDelegate)); + } +} diff --git a/Julia.NETstandard/src/Utils/JuliaUtils.cs b/Julia.NETstandard/src/Utils/JuliaUtils.cs new file mode 100644 index 0000000..a7276b2 --- /dev/null +++ b/Julia.NETstandard/src/Utils/JuliaUtils.cs @@ -0,0 +1,97 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; + +namespace JuliaNET.Utils +{ + public static class JuliaUtils + { + internal static string GetJuliaDir() + { + var proc = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "julia", + Arguments = @"-e ""println(\""JULIAPPPATH$(Sys.BINDIR)JULIAPPPATH\"")""", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + } + }; + proc.Start(); + var location = proc.StandardOutput.ReadToEnd(); + Regex rg = new("JULIAPPPATH(.+)JULIAPPPATH"); + var match = rg.Match(location); + + if (match.Success) + return match.Groups[1].Value; + + return null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public static unsafe T* ToPointer(this Span s) where T : unmanaged => (T*)Unsafe.AsPointer(ref s.GetPinnableReference()); + public static unsafe T* ToPointer(this T[] s) where T : unmanaged => (T*)GCHandle.Alloc(s, GCHandleType.Pinned).AddrOfPinnedObject(); + + public static T[,] ToMatrix(this T[][] source) where T : unmanaged + { + var dataOut = new T[source.Length, source[0].Length]; + var assertLength = source[0].Length; + + unsafe + { + for (var i = 0; i < source.Length; i++) + { + if (source[i].Length != assertLength) + { + throw new InvalidOperationException("The given jagged array is not rectangular."); + } + + fixed (T* pDataIn = source[i]) + { + fixed (T* pDataOut = &dataOut[i, 0]) + { + CopyBlockHelper.SmartCopy(pDataOut, pDataIn, assertLength); + } + } + } + } + + return dataOut; + } + + public static void PrintExp(this Exception x, + TextWriter tw = null) + { + tw ??= Console.Out; + tw.WriteLine(x.GetBaseException()); + + var st = new StackTrace(x, true); + var frames = st.GetFrames(); + + for (int i = 0; i < frames.Length; i++) + { + var frame = frames[i]; + if (frame.GetFileLineNumber() < 1) + continue; + tw.Write("File: " + frame.GetFileName()); + tw.Write(", Method:" + frame.GetMethod().Name); + tw.Write(", LineNumber: " + frame.GetFileLineNumber()); + if (i == frames.Length - 1) + { + tw.WriteLine(); + break; + } + + tw.WriteLine(" --> "); + } + } + + public static void Print(this T o) => Console.Write(o); + public static void Println(this T o) => Console.WriteLine(o); + } +} diff --git a/Julia.NETstandard/src/Utils/SharpReflect.cs b/Julia.NETstandard/src/Utils/SharpReflect.cs new file mode 100644 index 0000000..b8888da --- /dev/null +++ b/Julia.NETstandard/src/Utils/SharpReflect.cs @@ -0,0 +1,47 @@ +using System; +using System.Reflection; + +namespace JuliaNET.Utils +{ + public class EmptyClass + { + private EmptyClass() { } + } + + public class SharpReflect + { + public readonly static BindingFlags FLAGS = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | + BindingFlags.NonPublic; + + public static MethodInfo GetMethod(string methodName, + params Type[] types) => typeof(T).GetMethod(methodName, FLAGS, null, types, null); + + public static MethodInfo GetMethod(string methodName) => GetMethod(methodName, typeof(T1)); + public static MethodInfo GetMethod(string methodName) => GetMethod(methodName, typeof(T1), typeof(T2)); + public static MethodInfo GetMethod(string methodName) => GetMethod(methodName, typeof(T1), typeof(T2), typeof(T3)); + public static MethodInfo GetMethod(string methodName) => GetMethod(methodName, typeof(T1), typeof(T2), typeof(T3), typeof(T4)); + public static MethodInfo GetMethod(string methodName) => GetMethod(methodName, typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5)); + + public static MethodInfo GetMethod(Type t, + string methodName, + params Type[] types) => t.GetMethod(methodName, FLAGS, null, types, null); + + + public static ConstructorInfo GetConstructor(params Type[] types) => typeof(T).GetConstructor(FLAGS, null, types, null); + + public static ConstructorInfo GetConstructor(Type t, + params Type[] types) => t.GetConstructor(FLAGS, null, types, null); + + public static ConstructorInfo GetConstructor() => GetConstructor(typeof(T1)); + public static ConstructorInfo GetConstructor() => GetConstructor(typeof(T1), typeof(T2)); + public static ConstructorInfo GetConstructor() => GetConstructor(typeof(T1), typeof(T2), typeof(T3)); + public static ConstructorInfo GetConstructor() => GetConstructor(typeof(T1), typeof(T2), typeof(T3), typeof(T4)); + public static ConstructorInfo GetConstructor() => GetConstructor(typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5)); + + + public static FieldInfo GetField(string name) => typeof(T).GetField(name, FLAGS); + + public static FieldInfo GetField(Type t, + string name) => t.GetField(name, FLAGS); + } +} diff --git a/Julia.NETstandard/src/Utils/UnsafeStream.cs b/Julia.NETstandard/src/Utils/UnsafeStream.cs new file mode 100644 index 0000000..756d980 --- /dev/null +++ b/Julia.NETstandard/src/Utils/UnsafeStream.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace JuliaNET.Utils +{ + public unsafe class UnsafeStream + { + private byte[] _items; + private int _size; + private byte* _ptr; + public int Count => _size; + public byte* Begin => _ptr; + public byte* End => _ptr + _size; + + public bool Contains(byte* b) => Begin >= b && End < b; + + public UnsafeStream(int initCapacity = 4) + { + //Does not Free Handle + _items = Array.Empty(); + _size = 0; + Capacity = initCapacity; + } + + public UnsafeStream(byte[] items) + { + _items = items; + _size = items.Length; + } + + public int Capacity + { + get => _items.Length; + set => _ptr = Resize(value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected byte* Resize(int length) + { + if (length != _items.Length) + { + if (length > 0) + { + byte[] newItems = new byte[length]; //{} GC.AllocateUninitializedArray(length, true); + GCHandle.Alloc(newItems, GCHandleType.Pinned); + if (_size > 0) + Array.Copy(_items, newItems, _size); + _items = newItems; + fixed (byte* bptr = newItems) + return bptr; + } + + _items = Array.Empty(); + _size = 0; + return null; + } + + return _ptr; + } + + // public T[] ReadArray(int idx) where T : unmanaged + // { + // T[] v = new T[Read(idx)]; + // idx += sizeof(int); + // fixed (T* dptr = v) + // Unsafe.CopyBlock(dptr, (T*)(_ptr + idx), (uint)v.Length); + // return v; + // } + + // public T* WriteArray(T[] v, + // out int aptr) where T : unmanaged + // { + // var p = WriteArray(v.Length, out aptr); + // fixed (T* dptr = v) + // Unsafe.CopyBlock(p, dptr, (uint)(sizeof(T) * v.Length)); + // return p; + // } + + public T* WriteArray(int size, + out int aptr) where T : unmanaged + { + var p = (int*)WritePtr(size, out aptr, sizeof(int)); + *p++ = size; + return (T*)p; + } + + public int WriteList(List v) where T : unmanaged + { + int aptr; + var p = WriteArray(v.Count, out aptr); + for (int i = 0, n = v.Count; i < n; i++) + p[i] = v[i]; + return aptr; + } + + public T* WritePtr(int nel, + out int pptr, + int pad = 0) where T : unmanaged + { + pptr = EnsureSizeWrite(_size + sizeof(T) * nel + pad); + return (T*)(pptr + _ptr); + } + + public int Write(ref T v) where T : unmanaged + { + *WritePtr(1, out int aptr) = v; + return aptr; + } + + public int Write(T v) where T : unmanaged + { + *WritePtr(1, out int aptr) = v; + return aptr; + } + + public int EnsureSizeWrite(int size) + { + byte[] array = _items; + if ((uint)size >= (uint)array.Length) + { + int min = size + 1; + if (_items.Length < min) + { + int newCapacity = _items.Length == 0 ? 4 : _items.Length * 2; + if (newCapacity < min) + newCapacity = min; + Capacity = newCapacity; + } + } + + var loc = _size; + _size = size; + return loc; + } + + // public byte[] ToByteArray() + // { + // var bytes = new byte[Count]; + // fixed (byte* dest = bytes) + // Marshal.Copy(_ptr, dest, 0, (uint)Count); + // return bytes; + // } + // + // public byte* GetDataPointer(int idx) => _ptr + idx; + + // public ref T Read() where T : unmanaged => ref Read(_size); + // public ref T Read(int idx) where T : unmanaged => ref Unsafe.AsRef(_ptr + idx); + // public void SetCount(int p) => _size = p; + } +} diff --git a/Sandbox48/Program.cs b/Sandbox48/Program.cs new file mode 100644 index 0000000..36cbbad --- /dev/null +++ b/Sandbox48/Program.cs @@ -0,0 +1,31 @@ +using JuliaNET.Core; +using JuliaNET.Stdlib; +using JuliaNET.Utils; + +namespace Sandbox48 +{ + internal static class Program + { + public static void Main(string[] args) + { + var jo = new Options(); + // jo.LoadSystemImage = "my_sys_image_path"; + Julia.Init(jo); + + JModule myModule = Julia.Eval(@" + module T + f(m1, m2) = m1 .* m2 + end"); + + var m1 = new[] { 2, 3, 4 }; + var m2 = new[] { 3, 4, 5 }; + + Any y = myModule + .GetFunction("f") + .Invoke(new Any(m1), new Any(m2)); + string.Join(",", y).Println(); + + Julia.Exit(); + } + } +} diff --git a/Sandbox48/Properties/AssemblyInfo.cs b/Sandbox48/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8df8047 --- /dev/null +++ b/Sandbox48/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Sandbox48")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Sandbox48")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("DF199950-742F-4DA3-9170-AF5B097CDE70")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Sandbox48/Sandbox48.csproj b/Sandbox48/Sandbox48.csproj new file mode 100644 index 0000000..87f00fa --- /dev/null +++ b/Sandbox48/Sandbox48.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {DF199950-742F-4DA3-9170-AF5B097CDE70} + Exe + Properties + Sandbox48 + Sandbox48 + v4.8 + 512 + true + + + x64 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + x64 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + {614fed42-e1b9-4006-8d15-e96a974620fe} + Julia.NETstandard + + + + + + diff --git a/Test/BasicTests.cs b/Test/BasicTests.cs index 972f84c..7e637bb 100644 --- a/Test/BasicTests.cs +++ b/Test/BasicTests.cs @@ -2,7 +2,7 @@ using JuliaNET.Stdlib; using NUnit.Framework; -namespace JuliadotNETTest +namespace Test { public class Tests { diff --git a/Test/Test.csproj b/Test/Test.csproj index dba40ff..7e849db 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -7,14 +7,14 @@ - - - - + + + + - + diff --git a/TestStandard/App.config b/TestStandard/App.config new file mode 100644 index 0000000..6ea3a38 --- /dev/null +++ b/TestStandard/App.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TestStandard/MatrixTest.cs b/TestStandard/MatrixTest.cs new file mode 100644 index 0000000..9d1301d --- /dev/null +++ b/TestStandard/MatrixTest.cs @@ -0,0 +1,26 @@ +using JuliaNET.Utils; +using NUnit.Framework; + +namespace TestStandard +{ + public class MatrixTest + { + [Test] + public void JaggedArray_ShouldBecomeMatrix() + { + var jaggedArray = new[] { new[] { 1, 1 }, new[] { 2, 2 } }; + var matrix = jaggedArray.ToMatrix(); + var expected = new[,] { { 1, 1 }, { 2, 2 } }; + Assert.That(matrix, Is.EqualTo(expected)); + } + + [Test] + public void RectangularJaggedArray_ShouldBecomeMatrix() + { + var jaggedArray = new[] { new[] { 1, 1 }, new[] { 2, 2 }, new[] { 3, 3 } }; + var matrix = jaggedArray.ToMatrix(); + var expected = new[,] { { 1, 1 }, { 2, 2 }, { 3, 3 } }; + Assert.That(matrix, Is.EqualTo(expected)); + } + } +} diff --git a/TestStandard/Nunit/AnyCollectionEqualConstraint.cs b/TestStandard/Nunit/AnyCollectionEqualConstraint.cs new file mode 100644 index 0000000..5f2ef78 --- /dev/null +++ b/TestStandard/Nunit/AnyCollectionEqualConstraint.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using JuliaNET.Stdlib; +using NUnit.Framework.Constraints; + +namespace TestStandard.Nunit +{ + public class AnyCollectionEqualConstraint : Constraint + { + private readonly IEnumerable _expected; + + public AnyCollectionEqualConstraint(IEnumerable expected) : base(expected) + { + _expected = expected; + } + + public override string Description => string.Join(", ", _expected); + + public override ConstraintResult ApplyTo(TActual actual) + { + if (actual is IEnumerable any) + { + return new ConstraintResult(this, actual, NunitAnyCollectionEqualityComparer.AreEqual(_expected, any)); + } + + return null; + } + } +} diff --git a/TestStandard/Nunit/AnyEqualConstraint.cs b/TestStandard/Nunit/AnyEqualConstraint.cs new file mode 100644 index 0000000..f464444 --- /dev/null +++ b/TestStandard/Nunit/AnyEqualConstraint.cs @@ -0,0 +1,25 @@ +using JuliaNET.Stdlib; +using NUnit.Framework.Constraints; + +namespace TestStandard.Nunit +{ + public class AnyEqualConstraint : Constraint + { + private readonly Any _expected; + + public AnyEqualConstraint(Any expected) : base(expected) + { + _expected = expected; + } + + public override ConstraintResult ApplyTo(TActual actual) + { + if (actual is Any any) + { + return new ConstraintResult(this, actual, NunitAnyEqualityComparer.AreEqual(_expected, any)); + } + + return null; + } + } +} diff --git a/TestStandard/Nunit/Is.cs b/TestStandard/Nunit/Is.cs new file mode 100644 index 0000000..11a147c --- /dev/null +++ b/TestStandard/Nunit/Is.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using JuliaNET.Stdlib; + +namespace TestStandard.Nunit +{ + public class Is : NUnit.Framework.Is + { + public static AnyEqualConstraint EqualToJuliaValue(Any expected) + { + return new AnyEqualConstraint(expected); + } + + public static AnyCollectionEqualConstraint EqualToJuliaEnumerable(IEnumerable expected) + { + return new AnyCollectionEqualConstraint(expected); + } + } +} diff --git a/TestStandard/Nunit/NunitAnyCollectionEqualityComparer.cs b/TestStandard/Nunit/NunitAnyCollectionEqualityComparer.cs new file mode 100644 index 0000000..4f2b4fb --- /dev/null +++ b/TestStandard/Nunit/NunitAnyCollectionEqualityComparer.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using JuliaNET.Stdlib; + +namespace TestStandard.Nunit +{ + public class NunitAnyCollectionEqualityComparer + { + public static bool AreEqual(IEnumerable x, + IEnumerable y) + { + if (x == null && y == null) + { + return true; + } + + if (x == null || y == null) + { + return false; + } + + using var expectedEnum = x.GetEnumerator(); + using var actualEnum = y.GetEnumerator(); + + while (expectedEnum.MoveNext() && actualEnum.MoveNext()) + { + if (expectedEnum.Current != actualEnum.Current) + { + return false; + } + } + + return true; + } + } +} diff --git a/TestStandard/Nunit/NunitAnyEqualityComparer.cs b/TestStandard/Nunit/NunitAnyEqualityComparer.cs new file mode 100644 index 0000000..4e0624c --- /dev/null +++ b/TestStandard/Nunit/NunitAnyEqualityComparer.cs @@ -0,0 +1,23 @@ +using JuliaNET.Stdlib; + +namespace TestStandard.Nunit +{ + public class NunitAnyEqualityComparer + { + public static bool AreEqual(Any x, + Any y) + { + if (x == null && y == null) + { + return true; + } + + if (x == null || y == null) + { + return false; + } + + return x.Equals(y); + } + } +} diff --git a/TestStandard/Properties/AssemblyInfo.cs b/TestStandard/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e9657b5 --- /dev/null +++ b/TestStandard/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestStandard")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestStandard")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("564E4007-4138-4E80-830C-B8106099B649")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TestStandard/TestStandard.csproj b/TestStandard/TestStandard.csproj new file mode 100644 index 0000000..95cb303 --- /dev/null +++ b/TestStandard/TestStandard.csproj @@ -0,0 +1,86 @@ + + + + + + + Debug + AnyCPU + {564E4007-4138-4E80-830C-B8106099B649} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + TestStandard + TestStandard + v4.8 + 512 + 9 + + + x64 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x64 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll + + + + + + + + + + + + + + + + + + + + + + {614fed42-e1b9-4006-8d15-e96a974620fe} + Julia.NETstandard + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. + + + + + + + diff --git a/TestStandard/Tests.cs b/TestStandard/Tests.cs new file mode 100644 index 0000000..7de924e --- /dev/null +++ b/TestStandard/Tests.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using JuliaNET.Core; +using JuliaNET.Stdlib; +using JuliaNET.Utils; +using NUnit.Framework; + +namespace TestStandard +{ + public class Tests + { + [OneTimeSetUp] + public void Setup() => Julia.Init(); + + [OneTimeTearDown] + public void TearDown() => Julia.Exit(); + + [Test] + public void JuliaInitialized() + { + Assert.That(Julia.IsInitialized, Is.True, "Julia Not Initialized"); + } + + [Test] + public void TypeConversion() + { + Assert.Multiple(() => + { + Assert.That((int)(new Any(5) + 2), Is.EqualTo(5 + 2), "Integer Conversion Failure"); + Assert.That((string)new Any("Hi"), Is.EqualTo("Hi"), "String Conversion Failure"); + Assert.That(new Any(new[] { 2, 3, 4 }).Length, Is.EqualTo(3), "Array Conversion Failure"); + }); + } + + [Test] + public void ArrayMath() + { + var m1 = new[] { 2, 3, 4 }; + var m2 = new[] { 3, 4, 5 }; + JModule mod = Julia.Eval(@"module T; add(m1, m2) = m1 .+ m2;end"); + IEnumerable y = mod.GetFunction("add").Invoke(new Any(m1), new Any(m2)); + var expected = new[] { 5, 7, 9 }.Select(val => new Any(val)); + Assert.That(y, Nunit.Is.EqualToJuliaEnumerable(expected), "Array Add Failure"); + } + + [Test] + public void IntMatrixMath() + { + var m1 = new[,] { { 1, 1 }, { 2, 2 } }; + var m2 = new[,] { { 3, 3 }, { 4, 4 } }; + JModule mod = Julia.Eval(@"module T; add(m1, m2) = m1 .+ m2;end"); + IEnumerable y = mod.GetFunction("add").Invoke(new Any(m1), new Any(m2)); + // Rows and columns are reversed + var expected = new[,] { { 4, 6 }, { 4, 6 } }.Cast().Select(val => new Any(val)); + Assert.That(y, Nunit.Is.EqualToJuliaEnumerable(expected), "Matrix Add Failure"); + } + + [Test] + public void FloatMatrixMath() + { + var mArray1 = new[] { new[] { 1f, 1 }, new[] { 2f, 2 } }; + var mArray2 = new[] { new[] { 3f, 3 }, new[] { 4f, 4 } }; + // Jagged arrays need to be converted to multi-dimensional arrays + var m1 = mArray1.ToMatrix(); + var m2 = mArray2.ToMatrix(); + JModule mod = Julia.Eval(@"module T; add(m1, m2) = m1 .+ m2;end"); + IEnumerable y = mod.GetFunction("add").Invoke(new Any(m1), new Any(m2)); + // Rows and columns are reversed + var expected = new[,] { { 4f, 6 }, { 4, 6 } }.Cast().Select(val => new Any(val)); + Assert.That(y, Nunit.Is.EqualToJuliaEnumerable(expected), "Matrix Add Failure"); + } + } +} diff --git a/TestStandard/packages.config b/TestStandard/packages.config new file mode 100644 index 0000000..53f5027 --- /dev/null +++ b/TestStandard/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file