├── src ├── vm │ ├── runtimes │ │ ├── linux-x64 │ │ │ └── native │ │ │ │ ├── libneko.so │ │ │ │ ├── libneko.so.2 │ │ │ │ ├── std.ndll │ │ │ │ └── libneko.so.2.3.1 │ │ ├── osx-x64 │ │ │ └── native │ │ │ │ ├── libneko.dylib │ │ │ │ ├── libneko.2.dylib │ │ │ │ ├── std.ndll │ │ │ │ └── libneko.2.3.1.dylib │ │ └── win-x64 │ │ │ └── native │ │ │ ├── neko.dll │ │ │ ├── std.ndll │ │ │ └── gcmt-dll.dll │ ├── native │ │ ├── NekoVM.cs │ │ ├── NekoBuffer.cs │ │ ├── INativeCast.cs │ │ ├── INekoDisposable.cs │ │ ├── NekoValueType.cs │ │ ├── __unsafe_cast.cs │ │ ├── NekoValue.cs │ │ ├── delegates.cs │ │ ├── rawStructs.cs │ │ ├── NekoType.cs │ │ └── Native.cs │ ├── test.n │ ├── Properties │ │ ├── logo-2.png │ │ └── launchSettings.json │ ├── base │ │ ├── NekoFunctionKind.cs │ │ ├── NekoBehaviour.cs │ │ ├── types │ │ │ ├── NekoBool.cs │ │ │ ├── NekoInt32.cs │ │ │ ├── NekoString.cs │ │ │ ├── NekoException.cs │ │ │ ├── NekoNull.cs │ │ │ ├── NekoGlobal.cs │ │ │ ├── NekoFloat.cs │ │ │ ├── NekoArray.cs │ │ │ ├── NekoRuntimeObject.cs │ │ │ └── NekoFunction.cs │ │ ├── NekoLoader.cs │ │ ├── NekoAssert.cs │ │ ├── NekoException.cs │ │ ├── NekoModule.cs │ │ ├── NekoObject.cs │ │ ├── NekoMarshal.cs │ │ └── Neko.cs │ ├── tag.cs │ ├── extensions │ │ └── RangeEx.cs │ ├── test.neko │ └── vm.csproj ├── tools │ └── nekoc │ │ ├── logo-2.png │ │ ├── .config │ │ └── dotnet-tools.json │ │ ├── StringEx.cs │ │ ├── AppState.cs │ │ ├── dotnet-nekoc.csproj │ │ ├── HttpClientDownloadWithProgress.cs │ │ ├── GithubClient.cs │ │ └── Program.cs ├── test │ └── vm-base-test │ │ ├── unit.n │ │ ├── vm-base-test.csproj │ │ ├── unit-test.neko │ │ └── VMTests.cs └── host │ ├── Program.cs │ └── host.csproj ├── include ├── test.neko ├── neko_mod.h ├── neko_elf.h ├── neko_vm.h ├── hlc.h ├── neko.h └── hl.h ├── LICENSE ├── .github └── workflows │ └── code-maid.yml ├── neko.sln.DotSettings ├── neko.sln ├── README.md └── .gitignore /src/vm/runtimes/linux-x64/native/libneko.so: -------------------------------------------------------------------------------- 1 | libneko.so.2 -------------------------------------------------------------------------------- /src/vm/runtimes/linux-x64/native/libneko.so.2: -------------------------------------------------------------------------------- 1 | libneko.so.2.3.1 -------------------------------------------------------------------------------- /src/vm/runtimes/osx-x64/native/libneko.dylib: -------------------------------------------------------------------------------- 1 | libneko.2.dylib -------------------------------------------------------------------------------- /src/vm/runtimes/osx-x64/native/libneko.2.dylib: -------------------------------------------------------------------------------- 1 | libneko.2.3.1.dylib -------------------------------------------------------------------------------- /src/vm/native/NekoVM.cs: -------------------------------------------------------------------------------- 1 | namespace Neko 2 | { 3 | public struct NekoVM { } 4 | } -------------------------------------------------------------------------------- /src/vm/test.n: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/vm/test.n -------------------------------------------------------------------------------- /src/tools/nekoc/logo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/tools/nekoc/logo-2.png -------------------------------------------------------------------------------- /src/test/vm-base-test/unit.n: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/test/vm-base-test/unit.n -------------------------------------------------------------------------------- /src/vm/Properties/logo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/vm/Properties/logo-2.png -------------------------------------------------------------------------------- /src/vm/native/NekoBuffer.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | public struct NekoBuffer 4 | { } 5 | } -------------------------------------------------------------------------------- /src/vm/runtimes/linux-x64/native/std.ndll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/vm/runtimes/linux-x64/native/std.ndll -------------------------------------------------------------------------------- /src/vm/runtimes/osx-x64/native/std.ndll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/vm/runtimes/osx-x64/native/std.ndll -------------------------------------------------------------------------------- /src/vm/runtimes/win-x64/native/neko.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/vm/runtimes/win-x64/native/neko.dll -------------------------------------------------------------------------------- /src/vm/runtimes/win-x64/native/std.ndll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/vm/runtimes/win-x64/native/std.ndll -------------------------------------------------------------------------------- /src/vm/runtimes/win-x64/native/gcmt-dll.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/vm/runtimes/win-x64/native/gcmt-dll.dll -------------------------------------------------------------------------------- /src/vm/runtimes/linux-x64/native/libneko.so.2.3.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/vm/runtimes/linux-x64/native/libneko.so.2.3.1 -------------------------------------------------------------------------------- /src/vm/runtimes/osx-x64/native/libneko.2.3.1.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xF6/neko_vm_binding/HEAD/src/vm/runtimes/osx-x64/native/libneko.2.3.1.dylib -------------------------------------------------------------------------------- /src/vm/base/NekoFunctionKind.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | public enum NekoFunctionKind 4 | { 5 | Imported, 6 | Exported 7 | } 8 | } -------------------------------------------------------------------------------- /src/vm/native/INativeCast.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | public unsafe interface INativeCast where T : unmanaged 4 | { 5 | T* AsInternal(); 6 | } 7 | } -------------------------------------------------------------------------------- /include/test.neko: -------------------------------------------------------------------------------- 1 | $print("module loaded\n"); 2 | $exports.log = function() { 3 | $print("swack pidoras"); 4 | }; 5 | $exports.x = 33; 6 | $exports.f = function(x) { return x * 2 + 1; } -------------------------------------------------------------------------------- /src/vm/tag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("vm-base-test")] 4 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("host")] -------------------------------------------------------------------------------- /src/vm/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "nekoVM-proxy": { 4 | "commandName": "Project", 5 | "environmentVariables": { 6 | "NEKO_JIT_DEBUG": "OFF" 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/tools/nekoc/.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "ivysola.nekoc": { 6 | "version": "1.0.0", 7 | "commands": [ 8 | "nekoc" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/vm/native/INekoDisposable.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | using System; 4 | 5 | public interface INekoDisposable : IDisposable 6 | { 7 | void _release(); 8 | void IDisposable.Dispose() 9 | { 10 | _release(); 11 | // ReSharper disable once GCSuppressFinalizeForTypeWithoutDestructor 12 | GC.SuppressFinalize(this); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/host/Program.cs: -------------------------------------------------------------------------------- 1 | namespace neko.host 2 | { 3 | using System; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | using Neko.Base; 10 | using Neko.NativeRing; 11 | 12 | internal class Program 13 | { 14 | public static unsafe void Main(string[] args) 15 | { 16 | } 17 | } 18 | 19 | 20 | } 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/vm/native/NekoValueType.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | public enum NekoValueType : uint 4 | { 5 | VAL_INT = 0xFF, 6 | VAL_NULL = 0, 7 | VAL_FLOAT = 1, 8 | VAL_BOOL = 2, 9 | VAL_STRING = 3, 10 | VAL_OBJECT = 4, 11 | VAL_ARRAY = 5, 12 | VAL_FUNCTION = 6, 13 | VAL_ABSTRACT = 7, 14 | VAL_EXCEPTION = 9, 15 | VAL_PRIMITIVE = 6 | 16, 16 | VAL_JITFUN = 6 | 32, 17 | VAL_32_BITS = 0xFFFFFFFF 18 | } 19 | } -------------------------------------------------------------------------------- /src/vm/base/NekoBehaviour.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using NativeRing; 4 | 5 | public abstract unsafe class NekoBehaviour : INekoDisposable 6 | { 7 | protected internal NekoValue* @ref; 8 | protected internal NekoBehaviour(NekoValue* value) => @ref = value; 9 | 10 | ~NekoBehaviour() => (this as INekoDisposable)._release(); 11 | void INekoDisposable._release() => @ref = null; 12 | 13 | public static implicit operator NekoValue*(NekoBehaviour behaviour) => behaviour.@ref; 14 | } 15 | } -------------------------------------------------------------------------------- /src/tools/nekoc/StringEx.cs: -------------------------------------------------------------------------------- 1 | namespace nekoc 2 | { 3 | using System; 4 | using System.IO; 5 | 6 | public static class StringEx 7 | { 8 | public static string Emoji(this string str) => 9 | Environment.GetEnvironmentVariable("EMOJI_USE") == "0" 10 | ? "" 11 | : EmojiOne.EmojiOne.ShortnameToUnicode(str); 12 | 13 | public static DirectoryInfo AsDirectoryInfo(this string str) => new(str); 14 | public static FileInfo AsFileInfo(this string str) => new(str); 15 | } 16 | } -------------------------------------------------------------------------------- /src/host/host.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net5.0 6 | true 7 | 8 | 9 | 10 | x64 11 | true 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/vm/extensions/RangeEx.cs: -------------------------------------------------------------------------------- 1 | namespace Neko 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | public static class RangeEx 8 | { 9 | public static IEnumerable ForEach(this Range range, Func functor) 10 | => Enumerable.Range(range.Start.Value, range.End.Value - range.Start.Value).Select(functor); 11 | public static IEnumerator GetEnumerator(this Range range) 12 | => Enumerable.Range(range.Start.Value, range.End.Value - range.Start.Value).GetEnumerator(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/vm/native/__unsafe_cast.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | using Neko.Base; 4 | using System.Reflection; 5 | internal static unsafe class __unsafe_cast 6 | { 7 | public static void* _cdel(object o) 8 | { 9 | if (o is NekoBehaviour no) 10 | return no.@ref; 11 | return Pointer.Unbox(o); 12 | } 13 | public static object _cwel(void* o) => Pointer.Box(o, typeof(void*)); 14 | 15 | public static void* _cmp(MethodInfo info, params object[] args) => _cdel(info.Invoke(null, args)); 16 | public static void _cmv(MethodInfo info, params object[] args) => info.Invoke(null, args); 17 | } 18 | } -------------------------------------------------------------------------------- /src/vm/base/types/NekoBool.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using NativeRing; 4 | 5 | public sealed unsafe class NekoBool : NekoObject 6 | { 7 | public static readonly NekoBool True = new NekoBool(Native.v_true()); 8 | public static readonly NekoBool False = new NekoBool(Native.v_false()); 9 | 10 | internal NekoBool(NekoValue* value) : base(value) => NekoAssert.IsBool(value); 11 | 12 | 13 | public bool Value => this.@ref == Native.v_true(); 14 | 15 | public static implicit operator bool(NekoBool v) => v.Value; 16 | public static implicit operator NekoBool(bool v) => v ? new NekoBool(Native.v_true()) : new NekoBool(Native.v_false()); 17 | } 18 | } -------------------------------------------------------------------------------- /src/vm/base/types/NekoInt32.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using NativeRing; 5 | public sealed unsafe class NekoInt : NekoObject 6 | { 7 | internal NekoInt(NekoValue* value) : base(value) 8 | => NekoAssert.IsInt(value); 9 | 10 | public static implicit operator int(NekoInt i) 11 | { 12 | if (NekoType.is_null(i.@ref)) 13 | throw new NullReferenceNekoException(i.@ref); 14 | return ((((int)(IntPtr)(i.@ref)) >> 1)); 15 | } 16 | 17 | public static implicit operator NekoInt(int i) => 18 | new NekoInt(Native.neko_alloc_int(i)); 19 | 20 | public int Value => this; 21 | 22 | public override string ToString() => Value.ToString(); 23 | } 24 | } -------------------------------------------------------------------------------- /src/vm/base/types/NekoString.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using System.Runtime.InteropServices; 5 | using NativeRing; 6 | 7 | public unsafe class NekoString : NekoObject, INativeCast<_neko_string> 8 | { 9 | public override string ToString() 10 | => Marshal.PtrToStringUTF8((IntPtr)(&((_neko_string*)@ref)->c)); 11 | 12 | public static implicit operator string(NekoString str) 13 | => str.ToString(); 14 | public static implicit operator NekoString(string str) 15 | => new NekoString(Native.neko_alloc_string(str)); 16 | 17 | public string Value => ToString(); 18 | 19 | public _neko_string* AsInternal() => (_neko_string*)@ref; 20 | protected internal NekoString(NekoValue* value) : base(value) 21 | => NekoAssert.IsString(value); 22 | } 23 | } -------------------------------------------------------------------------------- /src/vm/base/types/NekoException.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using NativeRing; 5 | 6 | public sealed unsafe class NekoRuntimeException : NekoObject, INativeCast<__exception> 7 | { 8 | public string Message { get; } 9 | public int Line { get; } 10 | public string File { get; } 11 | public string Function { get; } 12 | internal NekoRuntimeException(NekoValue* value) : base(value) 13 | { 14 | __exception* raw = AsInternal(); 15 | 16 | Message = new NekoString((NekoValue*)raw->msg); 17 | File = new NekoString((NekoValue*)raw->file); 18 | Function = new NekoString((NekoValue*)raw->funcsig); 19 | Line = ((IntPtr)(raw->line)).ToInt32(); 20 | } 21 | 22 | 23 | 24 | public __exception* AsInternal() => (__exception*)this.@ref; 25 | } 26 | } -------------------------------------------------------------------------------- /src/vm/native/NekoValue.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | using System.Runtime.CompilerServices; 4 | using static NekoValueType; 5 | 6 | public unsafe struct NekoValue 7 | { 8 | public uint t; 9 | public NekoValueType GetValueType() 10 | { 11 | fixed (NekoValue* p = &this) 12 | { 13 | if (NekoType.is_function(p)) 14 | return VAL_FUNCTION; 15 | if (NekoType.is_array(p)) 16 | return VAL_ARRAY; 17 | if (NekoType.is_int(p)) 18 | return VAL_INT; 19 | if (NekoType.is_float(p)) 20 | return VAL_FLOAT; 21 | if (NekoType.is_object(p)) 22 | return VAL_OBJECT; 23 | return NekoType.is_string(p) ? 24 | VAL_STRING : 25 | NekoType.get_valtype(p); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/vm/native/delegates.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | using Base; 4 | 5 | internal unsafe delegate NekoObject oic(NekoValue* value); 6 | 7 | internal unsafe delegate void* nfd0(); 8 | internal unsafe delegate void* nfd1(void* x1); 9 | internal unsafe delegate void* nfd2(void* x1, void* x2); 10 | internal unsafe delegate void* nfd3(void* x1, void* x2, void* x3); 11 | internal unsafe delegate void* nfd4(void* x1, void* x2, void* x3, void* x4); 12 | internal unsafe delegate void* nfd5(void* x1, void* x2, void* x3, void* x4, void* x5); 13 | 14 | internal unsafe delegate void nad0(); 15 | internal unsafe delegate void nad1(void* x1); 16 | internal unsafe delegate void nad2(void* x1, void* x2); 17 | internal unsafe delegate void nad3(void* x1, void* x2, void* x3); 18 | internal unsafe delegate void nad4(void* x1, void* x2, void* x3, void* x4); 19 | internal unsafe delegate void nad5(void* x1, void* x2, void* x3, void* x4, void* x5); 20 | } -------------------------------------------------------------------------------- /src/vm/base/types/NekoNull.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using NativeRing; 5 | 6 | public sealed unsafe class NekoNull : NekoObject, IEquatable 7 | { 8 | internal NekoNull(NekoValue* value) : base(value) => NekoAssert.IsNull(value); 9 | 10 | 11 | #region Equality members 12 | 13 | public bool Equals(NekoNull other) => true; 14 | public override bool Equals(object obj) 15 | { 16 | if (obj is null) 17 | return true; 18 | return ReferenceEquals(this, obj) || obj is NekoNull other && Equals(other); 19 | } 20 | public override int GetHashCode() => base.GetHashCode(); 21 | public static bool operator ==(NekoNull left, NekoNull right) => Equals(left, right); 22 | 23 | public static bool operator !=(NekoNull left, NekoNull right) => !Equals(left, right); 24 | 25 | #endregion 26 | 27 | public object Value => null; 28 | } 29 | } -------------------------------------------------------------------------------- /src/test/vm-base-test/vm-base-test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | vm_base_test 6 | 7 | false 8 | 9 | 10 | 11 | x64 12 | true 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Always 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/vm/base/types/NekoGlobal.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using NativeRing; 5 | 6 | internal sealed unsafe class NekoGlobal : NekoRuntimeObject 7 | { 8 | internal NekoGlobal(NekoValue* value) : base(value) { } 9 | 10 | public NekoValueType @typeof(NekoValue* value) => 11 | (NekoValueType)((NekoInt)(new NekoFunction("typeof", base["typeof"].@ref)) 12 | .InvokeWithNative(value) /* wtf */ - 1); 13 | 14 | public NekoString smake(int size) => 15 | (NekoString)(new NekoFunction(nameof(smake), base[nameof(smake)].@ref)) 16 | .InvokeWithNative(Native.neko_alloc_int(size)); 17 | public NekoInt ssize(NekoString str) => 18 | (NekoInt)(new NekoFunction(nameof(ssize), base[nameof(ssize)].@ref)) 19 | .InvokeWithNative(str.@ref); 20 | [Obsolete("Not working...")] 21 | public NekoRuntimeObject @new(NekoObject value) => 22 | (NekoRuntimeObject)new NekoFunction("new", base["new"].@ref) 23 | .Invoke(value); 24 | } 25 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Yuuki Wesp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/vm/base/types/NekoFloat.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using NativeRing; 4 | 5 | public sealed unsafe class NekoFloat : NekoObject, INativeCast<_neko_float> 6 | { 7 | internal NekoFloat(NekoValue* value) : base(value) => NekoAssert.IsFloat(value); 8 | public _neko_float* AsInternal() => (_neko_float*)@ref; 9 | 10 | public static implicit operator float(NekoFloat i) 11 | { 12 | if (NekoType.is_null(i.@ref)) 13 | throw new NullReferenceNekoException(i.@ref); 14 | return (float)i.AsInternal()->f; 15 | } 16 | public static implicit operator double(NekoFloat i) 17 | { 18 | if (NekoType.is_null(i.@ref)) 19 | throw new NullReferenceNekoException(i.@ref); 20 | return i.AsInternal()->f; 21 | } 22 | 23 | public float GetValue() => this; 24 | 25 | public static implicit operator NekoFloat(float i) => 26 | new NekoFloat(Native.neko_alloc_float(i)); 27 | public static implicit operator NekoFloat(double i) => 28 | new NekoFloat(Native.neko_alloc_float(i)); 29 | } 30 | } -------------------------------------------------------------------------------- /src/vm/base/NekoLoader.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System.IO; 4 | using System.Linq; 5 | using NativeRing; 6 | 7 | public sealed unsafe class NekoLoader : NekoObject 8 | { 9 | internal NekoLoader(NekoValue* value) : base(value) { } 10 | 11 | public static NekoLoader CreateDefault() 12 | => new NekoLoader(Native.neko_default_loader(null, 0)); 13 | 14 | internal NekoModule Load(FileInfo file) 15 | { 16 | var args = stackalloc NekoValue*[2]; 17 | var exception = (NekoValue*)null; 18 | args[0] = Native.neko_alloc_string(file.ToString()); 19 | args[1] = this.@ref; 20 | 21 | var a1 = Native.neko_val_id("loadmodule"); 22 | var a2 = Native.neko_val_field(this.@ref, a1); 23 | var result = Native.neko_val_callEx(this.@ref, a2, args, 2, ref exception); 24 | if (exception == null) 25 | return new NekoModule(result); 26 | var b = Native.neko_alloc_buffer(null); 27 | Native.neko_val_buffer(b, exception); 28 | var raw = Native.neko_buffer_to_string(b); 29 | throw new ModuleLoadNekoException(file, new NekoString(raw)); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/tools/nekoc/AppState.cs: -------------------------------------------------------------------------------- 1 | namespace nekoc 2 | { 3 | using System; 4 | using System.IO; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | using static System.Environment.SpecialFolder; 8 | using static System.Environment; 9 | using static System.IO.Path; 10 | public class AppState 11 | { 12 | public static bool isTrace = false; 13 | public static bool forceInstall = false; 14 | 15 | 16 | public static DirectoryInfo GetFolderForCache() => 17 | new(Combine(GetFolderPath(ApplicationData), "dotnet-nekoc-cache", GetVersion())); 18 | 19 | public static string GetOS() 20 | { 21 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 22 | return "win"; 23 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 24 | return "linux"; 25 | if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 26 | return "osx"; 27 | throw new NotSupportedException(); 28 | } 29 | 30 | public static string GetVersion() => 31 | Assembly.GetEntryAssembly()? 32 | .GetCustomAttribute()? 33 | .InformationalVersion ?? "any"; 34 | } 35 | } -------------------------------------------------------------------------------- /.github/workflows/code-maid.yml: -------------------------------------------------------------------------------- 1 | name: Daily code format check 2 | on: 3 | schedule: 4 | - cron: 0 2 * * * 5 | jobs: 6 | dotnet-format: 7 | runs-on: windows-latest 8 | steps: 9 | - name: Install dotnet-format 10 | run: dotnet tool install -g dotnet-format 11 | 12 | - name: Checkout repo 13 | uses: actions/checkout@v2 14 | with: 15 | ref: ${{ github.head_ref }} 16 | 17 | - name: Run dotnet format 18 | id: format 19 | uses: jfversluis/dotnet-format@v1.0.5 20 | with: 21 | repo-token: ${{ secrets.GITHUB_TOKEN }} 22 | action: "fix" 23 | workspace: "neko.sln" 24 | 25 | - name: Commit files 26 | if: steps.format.outputs.has-changes == 'true' 27 | run: | 28 | git config --local user.name "Code Maid" 29 | git config --local user.email "code.maid@0xf6.moe" 30 | git commit -a -m 'Automated dotnet-format update' 31 | - name: Create Pull Request 32 | uses: peter-evans/create-pull-request@v3 33 | with: 34 | title: '[housekeeping] Automated PR to fix formatting errors' 35 | body: | 36 | Automated PR to fix formatting errors 37 | token: ${{ secrets.CODE_MAID_PAT }} 38 | committer: Code Maid 39 | author: Code Maid 40 | labels: code-quality ♻︎ 41 | assignees: 0xF6 42 | reviewers: 0xF6 43 | branch: code-quality/codeformatting 44 | -------------------------------------------------------------------------------- /src/vm/base/NekoAssert.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using NativeRing; 4 | using static NativeRing.NekoValueType; 5 | 6 | internal static unsafe class NekoAssert 7 | { 8 | public static void IsFunction(NekoValue* value) 9 | { 10 | if (!NekoType.is_function(value)) 11 | throw new InvalidTypeNekoException(VAL_FUNCTION, value); 12 | } 13 | public static void IsArray(NekoValue* value) 14 | { 15 | if (!NekoType.is_array(value)) 16 | throw new InvalidTypeNekoException(VAL_ARRAY, value); 17 | } 18 | 19 | public static void IsString(NekoValue* value) 20 | { 21 | if (!NekoType.is_string(value)) 22 | throw new InvalidTypeNekoException(VAL_STRING, value); 23 | } 24 | 25 | public static void IsFloat(NekoValue* value) 26 | { 27 | if (!NekoType.is_float(value)) 28 | throw new InvalidTypeNekoException(VAL_FLOAT, value); 29 | } 30 | public static void IsInt(NekoValue* value) 31 | { 32 | if (!NekoType.is_int(value)) 33 | throw new InvalidTypeNekoException(VAL_INT, value); 34 | } 35 | public static void IsNull(NekoValue* value) 36 | { 37 | if (!NekoType.is_null(value)) 38 | throw new InvalidTypeNekoException(VAL_NULL, value); 39 | } 40 | 41 | public static void IsRuntimeObject(NekoValue* value) 42 | { 43 | if (!NekoType.is_object(value)) 44 | throw new InvalidTypeNekoException(VAL_OBJECT, value); 45 | } 46 | 47 | public static void IsBool(NekoValue* value) 48 | { 49 | if (!NekoType.is_boolean(value)) 50 | throw new InvalidTypeNekoException(VAL_BOOL, value); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/test/vm-base-test/unit-test.neko: -------------------------------------------------------------------------------- 1 | $exports.testObject = function() { 2 | x => 0, 3 | y => -1, 4 | text => "the text", 5 | fn => function() {return 42;} 6 | }; 7 | $exports.setget_int = function(i) { 8 | $print(i); 9 | $print("\n"); 10 | if($typeof(i) != $tint){ 11 | $print("setget_int FAIL"); 12 | $print("\n"); 13 | return; 14 | } 15 | return i; 16 | } 17 | $exports.setget_float = function(i) { 18 | $print(i); 19 | $print("\n"); 20 | if($typeof(i) != $tfloat){ 21 | $print("setget_float FAIL"); 22 | $print("\n"); 23 | return; 24 | } 25 | return i; 26 | } 27 | $exports.setget_string = function(i) { 28 | $print(i); 29 | $print("\n"); 30 | if($typeof(i) != $tstring){ 31 | $print("setget_string FAIL"); 32 | $print("\n"); 33 | return; 34 | } 35 | return i; 36 | } 37 | $exports.setget_boolean = function(i) { 38 | $print(i); 39 | $print("\n"); 40 | if($typeof(i) != $tbool){ 41 | $print("setget_boolean FAIL"); 42 | $print("\n"); 43 | return; 44 | } 45 | return i; 46 | } 47 | $exports.getset_and_call_function = function(i) { 48 | $print(i); 49 | $print("\n"); 50 | if($typeof(i) != $tfunction){ 51 | $print("getset_and_call_function FAIL"); 52 | $print("\n"); 53 | return; 54 | } 55 | i(); 56 | return i; 57 | } 58 | $exports.setget_array = function(i) { 59 | $print(i); 60 | $print("\n"); 61 | if($typeof(i) != $tarray){ 62 | $print("setget_array FAIL"); 63 | $print("\n"); 64 | return; 65 | } 66 | return i; 67 | } 68 | $exports.new_array_empty = function(i){ 69 | var q = $amake(i); 70 | q = $array(); 71 | return $amake(i); 72 | } 73 | $exports.new_array = function(){ 74 | var a = $amake(4); 75 | a = $array("1",2.12,"test",true); 76 | return a; 77 | } -------------------------------------------------------------------------------- /src/vm/base/NekoException.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using System.IO; 5 | using NativeRing; 6 | 7 | public abstract class NekoException : Exception 8 | { 9 | protected NekoException() { } 10 | protected NekoException(string message) : base(message) { } 11 | } 12 | 13 | public sealed class NekoVMException : NekoException 14 | { 15 | private readonly NekoRuntimeException _exception; 16 | 17 | internal NekoVMException(NekoRuntimeException exception) : base(exception.Message) 18 | => _exception = exception; 19 | 20 | public override string Source 21 | => $"{_exception.Function} in {_exception.File}:{_exception.Line}"; 22 | public override string StackTrace 23 | => $" at {Source}{Environment.NewLine}{base.StackTrace}"; 24 | 25 | public override string ToString() => $"\nAssert Neko Exception [{_exception.Message}] \n{StackTrace}"; 26 | } 27 | 28 | public sealed class ModuleLoadNekoException : NekoException 29 | { 30 | public ModuleLoadNekoException(FileInfo file, string exception) 31 | : base($"Failed load module '{file.Name}' due to '{exception}'.") { } 32 | } 33 | 34 | public sealed unsafe class InvalidTypeNekoException : NekoException 35 | { 36 | public InvalidTypeNekoException(NekoValueType target, NekoValue* value) 37 | : base($"Type '{NekoType.get_valtype(value)}' is not '{target}'") { } 38 | } 39 | public sealed class TypeIsNotSupportNekoException : NekoException 40 | { 41 | public TypeIsNotSupportNekoException(string ty) 42 | : base($"'{ty}' is support type.") { } 43 | } 44 | 45 | public sealed unsafe class NullReferenceNekoException : NekoException 46 | { 47 | public NullReferenceNekoException(NekoValue* value) 48 | : base($"Address 0x{(IntPtr)value:X} is invalid and cannot convert to {typeof(T).Name} type.") { } 49 | } 50 | public sealed class InvalidArgumentNekoException : NekoException { } 51 | } -------------------------------------------------------------------------------- /src/tools/nekoc/dotnet-nekoc.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net5.0 6 | true 7 | nekoc 8 | ./nupkg 9 | 2.3.0-preview.4 10 | true 11 | MIT 12 | https://github.com/0xF6/neko_vm_binding 13 | logo-2.png 14 | https://github.com/0xF6/neko_vm_binding 15 | git 16 | Neko VM neko module compiler 17 | Yuuki Wesp, Haxe Foundation 18 | Yuuki Wesp, Haxe Foundation 19 | © 2020 Yuuki Wesp, © 2019 Haxe Foundation 20 | true 21 | preview 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | True 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/vm/base/types/NekoArray.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using NativeRing; 7 | 8 | public unsafe class NekoArray : NekoObject, IEnumerable, INativeCast<_neko_array>, ICollection 9 | { 10 | internal NekoArray(NekoValue* value) : base(value) => 11 | NekoAssert.IsArray(value); 12 | public NekoObject this[int i] 13 | { 14 | get => GetByIndex(i); 15 | set => SetByIndex(i, value); 16 | } 17 | public NekoObject GetByIndex(int index) 18 | => GetByIndexNative(index); 19 | public void SetByIndex(int index, NekoObject value) 20 | => SetByIndexNative(index, value.@ref); 21 | public void SetByIndexNative(int index, NekoValue* value) 22 | => (&((_neko_array*)@ref)->ptr)[index] = value; 23 | public NekoValue* GetByIndexNative(int index) 24 | => (&((_neko_array*)@ref)->ptr)[index]; 25 | 26 | public _neko_array* AsInternal() 27 | => (_neko_array*)@ref; 28 | 29 | public static NekoArray Alloc(int size) => Alloc((uint)size); 30 | public static NekoArray Alloc(uint size) 31 | { 32 | var arr = new NekoArray(Native.neko_alloc_array(size)); 33 | for (var i = 0; i < size; i++) 34 | arr[i] = Native.v_null(); 35 | return arr; 36 | } 37 | 38 | #region 39 | 40 | public IEnumerator GetEnumerator() 41 | { 42 | for (var i = 0; i != Native.neko_val_array_size(this); i++) 43 | yield return GetByIndex(i); 44 | } 45 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 46 | 47 | 48 | public void CopyTo(Array array, int index) 49 | => throw new NotSupportedException(); 50 | 51 | public int Count => Native.neko_val_array_size(this); 52 | public bool IsSynchronized => false; 53 | public object SyncRoot { get; } = new object(); 54 | 55 | #endregion 56 | } 57 | } -------------------------------------------------------------------------------- /neko.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | True 3 | True 4 | True 5 | True 6 | True 7 | True 8 | True 9 | True 10 | True 11 | True 12 | True 13 | True 14 | True 15 | True 16 | True 17 | True 18 | True 19 | 20 | True 21 | True -------------------------------------------------------------------------------- /src/vm/base/NekoModule.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Dynamic; 7 | using NativeRing; 8 | 9 | public sealed unsafe class NekoModule : NekoBehaviour 10 | { 11 | private DynamicNekoModuleProxy proxy { get; set; } 12 | 13 | internal NekoModule(NekoValue* value) : base(value) 14 | => proxy = new DynamicNekoModuleProxy(this); 15 | 16 | public NekoFunction this[string name] => NekoFunction.Create(this, name); 17 | 18 | 19 | public dynamic AsDynamic() => proxy; 20 | 21 | public __module* AsInternal() => (__module*)@ref; 22 | 23 | public struct __module 24 | { 25 | public void* jit; 26 | public uint nglobals; 27 | public uint nfields; 28 | public uint codesize; 29 | public NekoValue* name; 30 | public NekoValue** globals; 31 | public NekoValue** fields; 32 | public NekoValue* loader; 33 | public NekoValue* exports; 34 | public NekoValue* jit_gc; 35 | public NekoValue* dbgtbl; 36 | public NekoDebug* dbgidxs; 37 | public void* code; 38 | } 39 | 40 | public struct NekoDebug 41 | { 42 | public int @base; 43 | public uint bits; 44 | } 45 | 46 | public class DynamicNekoModuleProxy : DynamicObject 47 | { 48 | private readonly NekoModule _obj; 49 | 50 | internal DynamicNekoModuleProxy(NekoModule obj) => _obj = obj; 51 | 52 | 53 | 54 | public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 55 | { 56 | try 57 | { 58 | result = _obj[binder.Name].Invoke(args); 59 | return true; 60 | } 61 | catch (Exception e) 62 | { 63 | Trace.WriteLine(e); 64 | result = null; 65 | return false; 66 | } 67 | } 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/vm/base/NekoObject.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using NativeRing; 5 | 6 | public unsafe class NekoObject : NekoBehaviour 7 | { 8 | protected NekoObject(NekoValue* value) : base(value) { } 9 | public override int GetHashCode() => Native.neko_val_hash(this.@ref); 10 | public static NekoObject Create(NekoValue* value) 11 | { 12 | if (NekoType.is_null(value)) 13 | return new NekoNull(value); 14 | if (NekoType.is_int(value)) 15 | return new NekoInt(value); 16 | if (NekoType.is_exception(value)) 17 | return new NekoRuntimeException(value); 18 | if (NekoType.is_string(value)) 19 | return new NekoString(value); 20 | if (NekoType.is_float(value)) 21 | return new NekoFloat(value); 22 | if (NekoType.is_float(value)) 23 | return new NekoFloat(value); 24 | if (NekoType.is_array(value)) 25 | return new NekoArray(value); 26 | if (NekoType.is_object(value)) 27 | return new NekoRuntimeObject(value); 28 | if (NekoType.is_boolean(value)) 29 | return new NekoBool(value); 30 | return new NekoObject(value); 31 | } 32 | 33 | #region implicit operator 34 | public static implicit operator NekoObject(NekoValue* val) => Create(val); 35 | public static implicit operator NekoObject(string s) => (NekoString)s; 36 | public static implicit operator NekoObject(int s) => (NekoInt)s; 37 | public static implicit operator NekoObject(bool s) => (NekoBool)s; 38 | public static implicit operator NekoObject(float s) => (NekoFloat)s; 39 | public static implicit operator NekoObject(double s) => (NekoFloat)s; 40 | 41 | public static implicit operator string(NekoObject s) => (NekoString)s; 42 | public static implicit operator int(NekoObject s) => (NekoInt)s; 43 | public static implicit operator bool(NekoObject s) => (NekoBool)s; 44 | public static implicit operator float(NekoObject s) => (NekoFloat)s; 45 | public static implicit operator double(NekoObject s) => (NekoFloat)s; 46 | #endregion 47 | 48 | } 49 | } -------------------------------------------------------------------------------- /include/neko_mod.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C)2005-2017 Haxe Foundation 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | #ifndef _NEKO_MOD_H 23 | #define _NEKO_MOD_H 24 | #include "neko.h" 25 | 26 | typedef struct _neko_debug { 27 | int base; 28 | unsigned int bits; 29 | } neko_debug; 30 | 31 | typedef struct _neko_module { 32 | void *jit; 33 | unsigned int nglobals; 34 | unsigned int nfields; 35 | unsigned int codesize; 36 | value name; 37 | value *globals; 38 | value *fields; 39 | value loader; 40 | value exports; 41 | value dbgtbl; 42 | neko_debug *dbgidxs; 43 | int_val *code; 44 | value jit_gc; 45 | } neko_module; 46 | 47 | typedef void *readp; 48 | typedef int (*reader)( readp p, void *buf, int size ); 49 | 50 | typedef struct { 51 | char *p; 52 | int len; 53 | } string_pos; 54 | 55 | C_FUNCTION_BEGIN 56 | 57 | VEXTERN field neko_id_module; 58 | VEXTERN vkind neko_kind_module; 59 | EXTERN neko_module *neko_read_module( reader r, readp p, value loader ); 60 | EXTERN int neko_file_reader( readp p, void *buf, int size ); // FILE * 61 | EXTERN int neko_string_reader( readp p, void *buf, int size ); // string_pos * 62 | EXTERN value neko_select_file( value path, const char *file, const char *ext ); 63 | 64 | C_FUNCTION_END 65 | 66 | #endif 67 | /* ************************************************************************ */ 68 | -------------------------------------------------------------------------------- /neko.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30404.54 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "vm", "src\vm\vm.csproj", "{8457EB76-DB5D-4EFE-8A7C-DF84297D45C8}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "host", "src\host\host.csproj", "{DE00D05A-46C0-4228-8281-D813965341EC}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "vm-base-test", "src\test\vm-base-test\vm-base-test.csproj", "{19B3FD51-005B-4EEE-B8AF-BA18D726638A}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-nekoc", "src\tools\nekoc\dotnet-nekoc.csproj", "{CBE795D2-7B02-49CB-AAE5-B13BC9F56420}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {8457EB76-DB5D-4EFE-8A7C-DF84297D45C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {8457EB76-DB5D-4EFE-8A7C-DF84297D45C8}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {8457EB76-DB5D-4EFE-8A7C-DF84297D45C8}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {8457EB76-DB5D-4EFE-8A7C-DF84297D45C8}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {DE00D05A-46C0-4228-8281-D813965341EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {DE00D05A-46C0-4228-8281-D813965341EC}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {DE00D05A-46C0-4228-8281-D813965341EC}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {DE00D05A-46C0-4228-8281-D813965341EC}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {19B3FD51-005B-4EEE-B8AF-BA18D726638A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {19B3FD51-005B-4EEE-B8AF-BA18D726638A}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {19B3FD51-005B-4EEE-B8AF-BA18D726638A}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {19B3FD51-005B-4EEE-B8AF-BA18D726638A}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {CBE795D2-7B02-49CB-AAE5-B13BC9F56420}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {CBE795D2-7B02-49CB-AAE5-B13BC9F56420}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {CBE795D2-7B02-49CB-AAE5-B13BC9F56420}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {CBE795D2-7B02-49CB-AAE5-B13BC9F56420}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {6457CFCB-E602-4BD3-A2B7-BC1CF36C13F7} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /include/neko_elf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C)2016-2017 Haxe Foundation 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | #ifndef _NEKO_ELF_H 23 | #define _NEKO_ELF_H 24 | #include "neko.h" 25 | 26 | #ifdef __GNUC__ 27 | #ifdef ABI_ELF 28 | # define SEPARATE_SECTION_FOR_BYTECODE 29 | #endif 30 | #endif 31 | 32 | /* None of this is needed on non-ELF platforms... */ 33 | #ifdef SEPARATE_SECTION_FOR_BYTECODE 34 | 35 | #include 36 | #include 37 | 38 | #define elf_get_Ehdr(p,f) (elf_is_32() ? ((Elf32_Ehdr*)p)->f : ((Elf64_Ehdr*)p)->f) 39 | #define elf_get_Shdr(p,f) (elf_is_32() ? ((Elf32_Shdr*)p)->f : ((Elf64_Shdr*)p)->f) 40 | 41 | #define elf_set_Ehdr(p,f,v) { if (elf_is_32()) ((Elf32_Ehdr*)p)->f = v; else ((Elf64_Ehdr*)p)->f = v; } 42 | #define elf_set_Shdr(p,f,v) { if (elf_is_32()) ((Elf32_Shdr*)p)->f = v; else ((Elf64_Shdr*)p)->f = v; } 43 | 44 | C_FUNCTION_BEGIN 45 | 46 | VEXTERN int size_Ehdr; /* Big enough to hold Elf32_Ehdr or Elf64_Ehdr... */ 47 | VEXTERN int size_Shdr; /* Big enough to hold Elf32_Shdr or Elf64_Shdr... */ 48 | 49 | EXTERN value elf_read_header(FILE *exe); 50 | EXTERN int elf_is_32(); 51 | EXTERN value elf_read_section(FILE *exe, int sec, char *buf); 52 | EXTERN value elf_write_section(FILE *exe, int sec, char *buf); 53 | EXTERN int elf_find_bytecode_section(FILE *exe); 54 | EXTERN void elf_free_section_string_table(); 55 | EXTERN value elf_find_embedded_bytecode(const char *file, int *beg, int *end); 56 | EXTERN int elf_find_bytecode_section(FILE *exe); 57 | 58 | C_FUNCTION_END 59 | 60 | #endif 61 | 62 | #endif 63 | /* ************************************************************************ */ 64 | -------------------------------------------------------------------------------- /src/vm/native/rawStructs.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | using System; 4 | using System.Runtime.InteropServices; 5 | 6 | [StructLayout(LayoutKind.Sequential, Pack = 4)] 7 | public unsafe struct _neko_cell 8 | { 9 | public int hkey; 10 | public NekoValue key; 11 | public NekoValue val; 12 | public _neko_cell* next; 13 | } 14 | [StructLayout(LayoutKind.Sequential, Pack = 4)] 15 | public unsafe struct _neko_hash 16 | { 17 | public _neko_cell** cells; 18 | public int ncells; 19 | public int nitems; 20 | } 21 | 22 | [StructLayout(LayoutKind.Sequential, Pack = 4)] 23 | public struct _neko_int32 24 | { 25 | public uint t; 26 | public int i; 27 | } 28 | [StructLayout(LayoutKind.Sequential, Pack = 4)] 29 | public struct _neko_float 30 | { 31 | public uint t; 32 | public double f; 33 | } 34 | 35 | public unsafe struct _neko_array 36 | { 37 | public uint t; 38 | public NekoValue* ptr; 39 | } 40 | 41 | public unsafe struct _neko_string 42 | { 43 | public uint t; 44 | public char c; 45 | } 46 | public unsafe struct _neko_function 47 | { 48 | public uint t; 49 | public int nargs; 50 | public void* addr; 51 | public NekoValue* env; 52 | public void* module; 53 | } 54 | 55 | public unsafe struct _neko_vm 56 | { 57 | public IntPtr sp; 58 | public IntPtr csp; 59 | public NekoValue* env; 60 | public NekoValue* vthis; 61 | public IntPtr spmin; 62 | public IntPtr spmax; 63 | public IntPtr trap; 64 | public void* jit_val; 65 | public void* jmp_buf; 66 | public int run_jit; 67 | public NekoValue* exc_stack; 68 | public void* print; 69 | public void* print_param; 70 | public void* clist; 71 | public NekoValue* resolver; 72 | public fixed char tmp[100]; 73 | public int trusted_code; 74 | } 75 | 76 | public unsafe struct _neko_objcell 77 | { 78 | public int id; 79 | public NekoValue* v; 80 | } 81 | public unsafe struct _neko_objtable 82 | { 83 | public int count; 84 | public _neko_objcell* cells; 85 | } 86 | public unsafe struct _runtime_obj 87 | { 88 | public uint t; 89 | public _neko_objtable table; 90 | public void* proto; 91 | } 92 | 93 | public unsafe struct __exception 94 | { 95 | public uint t; 96 | public _neko_string* msg; 97 | public nint line; 98 | public _neko_string* file; 99 | public _neko_string* funcsig; 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![NekoVM](https://user-images.githubusercontent.com/13326808/91330033-927bf600-e7d1-11ea-81a3-18be0ca9a065.png) 2 | 3 | 4 |

5 | Neko Virtual Machine for C# 😺 6 |

7 | 8 |

9 | For VM docs see NekoVM 10 |

11 | 12 | 13 | 14 |

15 | 16 | 17 | 18 | 19 | Telegram 20 | 21 |

22 |

23 | 24 | 25 | 26 | 27 | 28 |

29 | 30 | 31 |

32 | Deprecated as of 2021-09-09 33 |

34 |

35 | See HaxeFoundation/neko 36 |

37 | 38 | 39 | 40 | 41 | ```powershell 42 | Install-Package Ivy.NekoVM -Version 2.3.1-preview.6 43 | ``` 44 | 45 | 46 | ## 🧬 Roadmap 47 | 48 | - [ ] Documentation 49 | - [ ] Improved API 50 | - [x] Marshaling default types (without `vabstract` and `vkind`) 51 | - [x] Marshaling POCO object 52 | - [ ] Marshaling neko std types 53 | - [ ] Marshaling non-primitive .NET types 54 | - [ ] More tests 55 | - [x] Define global functions on runtime 56 | - [ ] Improved Thread support 57 | - [ ] Remove binaries from repo (automatization build for this) 58 | - [x] dotnet global tools neko compiler 59 | - [x] win-x64 60 | - [x] osx-x64 (need help with testing) 61 | - [x] linux-x64 62 | 63 | ### 💫 Fast start 64 | 65 | ```csharp 66 | using var vm = new Neko(); 67 | ``` 68 | 69 | ### Load *.n modules 70 | 71 | ```csharp 72 | var module = vm.LoadModule(new FileInfo("module.n")); 73 | ``` 74 | 75 | 76 | ### Get exports from module 77 | 78 | 79 | ```haxe 80 | // module.n 81 | $exports.GetInt = function() { 82 | return 42; 83 | } 84 | ``` 85 | 86 | ```csharp 87 | using var vm = new Neko(); 88 | var module = vm.LoadModule(new FileInfo("module.n")); 89 | Console.WriteLine(module["GetInt"].Invoke()); // NekoInt32 { Value: 42 } 90 | ``` 91 | 92 | 93 | ### Threading 94 | 95 | Each time you are going to use a VM API outside of the thread in which it was created, use the following code 96 | 97 | ```csharp 98 | vm.GuardBarrier() 99 | ``` 100 | 101 | Also, `vm.ThreadID` id managed thread in which it was created (see `Thread.CurrentThread.ManagedThreadId`) 102 | 103 | 104 | ### Install compiler 105 | 106 | ```poweshell 107 | dotnet tool install --global dotnet-nekoc --version 2.3.0-preview.2 108 | ``` 109 | -------------------------------------------------------------------------------- /include/neko_vm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C)2005-2017 Haxe Foundation 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | #ifndef _NEKO_VM_H 23 | #define _NEKO_VM_H 24 | #include "neko.h" 25 | 26 | typedef void (*neko_printer)( const char *data, int size, void *param ); 27 | typedef void (*thread_main_func)( void *param ); 28 | 29 | typedef struct _neko_vm neko_vm; 30 | 31 | typedef void (*neko_stat_func)( neko_vm *vm, const char *kind, int start ); 32 | 33 | C_FUNCTION_BEGIN 34 | 35 | EXTERN void neko_global_init(); 36 | EXTERN void neko_global_free(); 37 | EXTERN void neko_gc_major(); 38 | EXTERN void neko_gc_loop(); 39 | EXTERN void neko_gc_stats( int *heap, int *free ); 40 | EXTERN int neko_thread_create( thread_main_func init, thread_main_func main, void *param, void **handle ); 41 | EXTERN void neko_thread_blocking( thread_main_func f, void *p ); 42 | EXTERN bool neko_thread_register( bool t ); 43 | 44 | EXTERN neko_vm *neko_vm_alloc( void *unused ); 45 | EXTERN neko_vm *neko_vm_current(); 46 | EXTERN value neko_exc_stack( neko_vm *vm ); 47 | EXTERN value neko_call_stack( neko_vm *vm ); 48 | EXTERN void *neko_vm_custom( neko_vm *vm, vkind k ); 49 | EXTERN void neko_vm_set_custom( neko_vm *vm, vkind k, void *v ); 50 | EXTERN value neko_vm_execute( neko_vm *vm, void *module ); 51 | EXTERN void neko_vm_select( neko_vm *vm ); 52 | EXTERN int neko_vm_jit( neko_vm *vm, int enable_jit ); 53 | EXTERN int neko_vm_trusted( neko_vm *vm, int trusted ); 54 | EXTERN value neko_default_loader( char **argv, int argc ); 55 | EXTERN void neko_vm_redirect( neko_vm *vm, neko_printer print, void *param ); 56 | EXTERN void neko_vm_set_stats( neko_vm *vm, neko_stat_func fstats, neko_stat_func pstats ); 57 | EXTERN void neko_vm_dump_stack( neko_vm *vm ); 58 | 59 | EXTERN int neko_is_big_endian(); 60 | 61 | C_FUNCTION_END 62 | 63 | #endif 64 | /* ************************************************************************ */ 65 | -------------------------------------------------------------------------------- /src/vm/test.neko: -------------------------------------------------------------------------------- 1 | $print("module loaded\n"); 2 | $exports.log = function() { 3 | $print("swack pidoras"); 4 | }; 5 | $exports.ttw = function(f) { 6 | f(); 7 | $exports.xuy = f; 8 | } 9 | $exports.x = 33; 10 | $exports.f = function(x) { return x * 2 + 1; } 11 | 12 | $exports.getSizeStr = function(str) { 13 | $print($ssize(str)); 14 | return $ssize(str); 15 | } 16 | $exports.assert_int = function(i) { 17 | $print(i); 18 | $print("\n"); 19 | if($typeof(i) != $tint){ 20 | $print("assert_int FAIL"); 21 | $print("\n"); 22 | } 23 | return i; 24 | } 25 | $exports.assert_string = function(i) { 26 | $print(i); 27 | $print("\n"); 28 | if($typeof(i) != $tstring){ 29 | $print("test_string FAIL"); 30 | $print("\n"); 31 | } 32 | return i; 33 | } 34 | $exports.assert_boolean = function(i) { 35 | $print(i); 36 | $print("\n"); 37 | if($typeof(i) != $tbool){ 38 | $print("assert_boolean FAIL"); 39 | $print("\n"); 40 | } 41 | return i; 42 | } 43 | $exports.assert_boolean_true = function() { 44 | return true; 45 | } 46 | $exports.assert_boolean_false = function() { 47 | return false; 48 | } 49 | $exports.assert_function = function(i) { 50 | $print(i); 51 | $print("\n"); 52 | if($typeof(i) != $tfunction){ 53 | $print("assert_function FAIL"); 54 | $print("\n"); 55 | } 56 | i(); 57 | return i; 58 | } 59 | 60 | $exports.ttdarr = function() { 61 | return $amake(3); 62 | } 63 | $exports.dws = function() { 64 | var a = $amake(4); 65 | a = $array("1","3","test", 12); 66 | $print(a); 67 | $print($asize(a)); 68 | $print("\n"); 69 | return a; 70 | } 71 | $exports.dws2 = function() { 72 | var a = $amake(4); 73 | a = $array("1","3","test", 12); 74 | $print(a); 75 | $print($asize(a)); 76 | $print("\n"); 77 | return a; 78 | } 79 | $exports.dws3 = function() { 80 | var a = $amake(6); 81 | a = $array("1","3","test", 12, 14, 15); 82 | $print(a); 83 | $print($asize(a)); 84 | $print("\n"); 85 | return a; 86 | } 87 | $exports.test_null = function(t) { 88 | if ($typeof(i) != $tnull){ 89 | $print("test_null FAIL"); 90 | $print("\n"); 91 | } 92 | return; 93 | } 94 | $exports.new_empty_obj = function(){ 95 | return $new(null); 96 | } 97 | 98 | $exports.new_obj = function(){ 99 | return { 100 | x => 0, 101 | y => -1, 102 | msg => "hello" 103 | }; 104 | } 105 | $exports.test_array = function(s){ 106 | $print("test_array"); 107 | var a1 = $amake(3); 108 | $print(a1); 109 | $print(s); 110 | return; 111 | } 112 | $exports.test_array2 = function(s){ 113 | $print("test_array2"); 114 | var a1 = $amake(3); 115 | $print(a1); 116 | $print(s); 117 | return; 118 | } 119 | 120 | $exports.testObject = function(o){ 121 | $print(o); 122 | return; 123 | } -------------------------------------------------------------------------------- /src/vm/vm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library 4 | net5.0 5 | Neko 6 | true 7 | x64 8 | true 9 | preview 10 | 2.3.1-preview.6 11 | latest 12 | 13 | 14 | 15 | 16 | True 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Always 39 | 40 | 41 | 42 | 43 | MIT 44 | true 45 | neko, vm, nekovm, haxe, haxevm, bindings 46 | C# Bindings for NekoVM 47 | git 48 | https://github.com/0xF6/neko_vm_binding 49 | https://github.com/0xF6/neko_vm_binding 50 | 51 | Yuuki Wesp 52 | Yuuki Wesp 53 | NekoVM Bindings 54 | 2020 (C) Yuuki Wesp, 2015-2017 Haxe Foundation 55 | logo-2.png 56 | Ivy.NekoVM 57 | 58 | -------------------------------------------------------------------------------- /src/vm/native/NekoType.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | using System; 4 | using System.Linq; 5 | using System.Reflection; 6 | using Base; 7 | public unsafe ref struct NekoType 8 | { 9 | private const int NEKO_TAG_BITS = 4; 10 | 11 | 12 | 13 | public static NekoValueType tag(void* v) 14 | { 15 | if (v == null) 16 | return NekoValueType.VAL_NULL; 17 | return *(NekoValueType*)v; 18 | } 19 | 20 | public static uint short_tag(void* v) 21 | => (uint)tag(v) & ((1 << NEKO_TAG_BITS) - 1); 22 | public static bool is_int(void* v) 23 | => ((long)(IntPtr)v & 1) != 0; 24 | public static bool is_float(void* v) 25 | => (!is_int(v) && tag(v) == NekoValueType.VAL_FLOAT); 26 | public static bool is_object(void* v) 27 | => (!is_int(v) && tag(v) == NekoValueType.VAL_OBJECT); 28 | public static bool is_abstract(void* v) 29 | => (!is_int(v) && tag(v) == NekoValueType.VAL_ABSTRACT); 30 | public static bool is_string(void* v) 31 | => (!is_int(v) && short_tag(v) == (uint)NekoValueType.VAL_STRING); 32 | public static bool is_function(void* v) 33 | => (!is_int(v) && short_tag(v) == (uint)NekoValueType.VAL_FUNCTION); 34 | public static bool is_array(void* v) 35 | => (!is_int(v) && short_tag(v) == (uint)NekoValueType.VAL_ARRAY); 36 | public static bool is_boolean(void* v) 37 | => (tag(v) == NekoValueType.VAL_BOOL); 38 | public static bool is_exception(void* v) 39 | => (tag(v) == NekoValueType.VAL_EXCEPTION); 40 | 41 | public static bool is_null(void* v) 42 | => get_valtype(v) == NekoValueType.VAL_NULL; 43 | public static NekoValueType get_valtype(void* v) 44 | => (NekoValueType)(is_int(v) ? (uint)NekoValueType.VAL_INT : short_tag(v)); 45 | 46 | 47 | internal static bool IsCompatibleBackward(Type t) 48 | { 49 | if (new[] { typeof(void*), typeof(nint), typeof(nuint) }.Any(x => x == t)) 50 | return true; 51 | return t?.IsSubclassOf(typeof(NekoBehaviour)) ?? false; 52 | } 53 | 54 | internal static bool IsCompatibleForward(Type t) 55 | { 56 | if (t == typeof(string)) 57 | return true; 58 | if (t.IsSubclassOf(typeof(NekoBehaviour))) 59 | return true; 60 | if (t.IsPrimitive && (typeof(ulong) != t && typeof(long) != t)) 61 | return true; 62 | return false; 63 | } 64 | 65 | public static bool IsCompatible(ParameterInfo t, bool marshaling = false) 66 | => IsCompatible(t.ParameterType, marshaling); 67 | 68 | public static bool IsCompatible(MemberInfo t, bool marshaling = false) 69 | => IsCompatible(t.DeclaringType, marshaling); 70 | public static bool IsCompatible(Type t, bool marshaling = false) 71 | => !marshaling ? IsCompatibleBackward(t) : IsCompatibleForward(t); 72 | } 73 | } -------------------------------------------------------------------------------- /include/hlc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C)2005-2016 Haxe Foundation 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | #ifndef HLC_H 23 | #define HLC_H 24 | 25 | #include 26 | #include 27 | 28 | #ifdef HL_64 29 | # define PAD_64_VAL ,0 30 | #else 31 | # define PAD_64_VAL 32 | #endif 33 | 34 | #ifdef HLC_BOOT 35 | 36 | // undefine some commonly used names that can clash with class/var name 37 | #undef CONST 38 | #undef stdin 39 | #undef stdout 40 | #undef stderr 41 | #undef DELETE 42 | #undef NO_ERROR 43 | #undef EOF 44 | #undef STRICT 45 | #undef TRUE 46 | #undef FALSE 47 | #undef CW_USEDEFAULT 48 | #undef HIDDEN 49 | #undef RESIZABLE 50 | 51 | // disable some warnings triggered by HLC code generator 52 | 53 | #ifdef HL_VCC 54 | # pragma warning(disable:4100) // unreferenced param 55 | # pragma warning(disable:4101) // unreferenced local var 56 | # pragma warning(disable:4102) // unreferenced label 57 | # pragma warning(disable:4204) // nonstandard extension 58 | # pragma warning(disable:4221) // nonstandard extension 59 | # pragma warning(disable:4244) // possible loss of data 60 | # pragma warning(disable:4700) // uninitialized local variable used 61 | # pragma warning(disable:4701) // potentially uninitialized local variable 62 | # pragma warning(disable:4702) // unreachable code 63 | # pragma warning(disable:4703) // potentially uninitialized local 64 | # pragma warning(disable:4715) // control paths must return a value 65 | # pragma warning(disable:4716) // must return a value (ends with throw) 66 | # pragma warning(disable:4723) // potential divide by 0 67 | #else 68 | # pragma GCC diagnostic ignored "-Wunused-variable" 69 | # pragma GCC diagnostic ignored "-Wunused-function" 70 | # pragma GCC diagnostic ignored "-Wcomment" // comment in comment 71 | # ifdef HL_CLANG 72 | # pragma GCC diagnostic ignored "-Wreturn-type" 73 | # pragma GCC diagnostic ignored "-Wsometimes-uninitialized" 74 | # else 75 | # pragma GCC diagnostic ignored "-Wunused-but-set-variable" 76 | # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 77 | # endif 78 | #endif 79 | 80 | #endif 81 | 82 | extern void *hlc_static_call(void *fun, hl_type *t, void **args, vdynamic *out); 83 | extern void *hlc_get_wrapper(hl_type *t); 84 | extern void hl_entry_point(); 85 | 86 | #define HL__ENUM_CONSTRUCT__ hl_type *t; int index; 87 | #define HL__ENUM_INDEX__(v) ((venum*)(v))->index 88 | 89 | #endif -------------------------------------------------------------------------------- /src/vm/base/types/NekoRuntimeObject.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Dynamic; 8 | using System.Linq; 9 | using NativeRing; 10 | public unsafe class NekoRuntimeObject : NekoObject, INativeCast<_runtime_obj>, IEnumerable 11 | { 12 | private DynamicNekoObjectProxy proxy { get; } 13 | internal NekoRuntimeObject(NekoValue* value) : base(value) 14 | { 15 | NekoAssert.IsRuntimeObject(value); 16 | proxy = new DynamicNekoObjectProxy(this); 17 | } 18 | 19 | public NekoObject this[string name] 20 | { 21 | get => Native.neko_val_field(@ref, Native.neko_val_id(name)); 22 | set => Native.neko_alloc_field(@ref, Native.neko_val_id(name), value); 23 | } 24 | 25 | public dynamic AsDynamic() => proxy; 26 | 27 | public _runtime_obj* AsInternal() => (_runtime_obj*)@ref; 28 | 29 | public string[] GetFields() => 30 | (..AsInternal()->table.count) 31 | .ForEach(x => *&((_runtime_obj*)@ref)->table.cells[x]) 32 | .Select(x => (NekoObject)Native.neko_val_field_name(x.id)) 33 | .Cast() 34 | .Select(x => x.Value) 35 | .ToArray(); 36 | 37 | 38 | public static NekoRuntimeObject Alloc() 39 | => new NekoRuntimeObject(Native.neko_alloc_object(null)); 40 | 41 | public static NekoRuntimeObject From(object o) 42 | { 43 | var runtimeObject = Alloc(); 44 | var t = o.GetType(); 45 | 46 | var props = t.GetProperties(); 47 | var fields = t.GetFields(); 48 | 49 | 50 | foreach (var prop in props) 51 | { 52 | if (!NekoType.IsCompatible(prop.PropertyType, true)) 53 | continue; 54 | try 55 | { 56 | runtimeObject[prop.Name] = NekoMarshal.CLRToPrt(prop.GetValue(o)); 57 | } 58 | catch { } 59 | } 60 | foreach (var field in fields) 61 | { 62 | if (!NekoType.IsCompatible(field.FieldType, true)) 63 | continue; 64 | runtimeObject[field.Name] = NekoMarshal.CLRToPrt(field.GetValue(o)); 65 | } 66 | return runtimeObject; 67 | } 68 | 69 | 70 | public class DynamicNekoObjectProxy : DynamicObject 71 | { 72 | private readonly NekoRuntimeObject _obj; 73 | 74 | internal DynamicNekoObjectProxy(NekoRuntimeObject obj) => _obj = obj; 75 | 76 | public override IEnumerable GetDynamicMemberNames() => _obj.GetFields(); 77 | 78 | public override bool TryGetMember(GetMemberBinder binder, out object result) 79 | { 80 | try 81 | { 82 | result = (NekoObject)Native.neko_val_field(_obj.@ref, Native.neko_val_id(binder.Name)); 83 | return true; 84 | } 85 | catch (Exception e) 86 | { 87 | Trace.WriteLine(e); 88 | result = null; 89 | return false; 90 | } 91 | } 92 | } 93 | public IEnumerator GetEnumerator() 94 | => GetFields().Select(field => this[field]).GetEnumerator(); 95 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 96 | } 97 | } -------------------------------------------------------------------------------- /src/tools/nekoc/HttpClientDownloadWithProgress.cs: -------------------------------------------------------------------------------- 1 | namespace nekoc 2 | { 3 | using System; 4 | using System.IO; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | 8 | public class HttpClientDownloadWithProgress : IDisposable 9 | { 10 | private readonly string _downloadUrl; 11 | private readonly string _destinationFilePath; 12 | 13 | private HttpClient _httpClient; 14 | 15 | public delegate void ProgressChangedHandler(long? totalFileSize, long totalBytesDownloaded, 16 | double? progressPercentage); 17 | 18 | public event ProgressChangedHandler ProgressChanged; 19 | 20 | public HttpClientDownloadWithProgress(string downloadUrl, string destinationFilePath) 21 | { 22 | _downloadUrl = downloadUrl; 23 | _destinationFilePath = destinationFilePath; 24 | } 25 | 26 | 27 | public static HttpClientDownloadWithProgress Create(string downloadUrl, FileInfo destination) 28 | { 29 | return new HttpClientDownloadWithProgress(downloadUrl, destination.FullName); 30 | } 31 | 32 | public async Task StartDownload() 33 | { 34 | _httpClient = new HttpClient 35 | { 36 | Timeout = TimeSpan.FromSeconds(30) 37 | }; 38 | 39 | using var response = await _httpClient.GetAsync(_downloadUrl, HttpCompletionOption.ResponseHeadersRead); 40 | await DownloadFileFromHttpResponseMessage(response); 41 | } 42 | 43 | private async Task DownloadFileFromHttpResponseMessage(HttpResponseMessage response) 44 | { 45 | response.EnsureSuccessStatusCode(); 46 | 47 | var totalBytes = response.Content.Headers.ContentLength; 48 | 49 | await using var contentStream = await response.Content.ReadAsStreamAsync(); 50 | await ProcessContentStream(totalBytes, contentStream); 51 | } 52 | private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream) 53 | { 54 | var totalBytesRead = 0L; 55 | var readCount = 0L; 56 | var buffer = new byte[8192]; 57 | var isMoreToRead = true; 58 | 59 | await using var fileStream = new FileStream(_destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true); 60 | do 61 | { 62 | var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length); 63 | if (bytesRead == 0) 64 | { 65 | isMoreToRead = false; 66 | TriggerProgressChanged(totalDownloadSize, totalBytesRead); 67 | continue; 68 | } 69 | 70 | await fileStream.WriteAsync(buffer, 0, bytesRead); 71 | 72 | totalBytesRead += bytesRead; 73 | readCount += 1; 74 | 75 | if (readCount % 100 == 0) 76 | TriggerProgressChanged(totalDownloadSize, totalBytesRead); 77 | } 78 | while (isMoreToRead); 79 | } 80 | 81 | private void TriggerProgressChanged(long? totalDownloadSize, long totalBytesRead) 82 | { 83 | if (ProgressChanged == null) 84 | return; 85 | 86 | double? progressPercentage = null; 87 | if (totalDownloadSize.HasValue) 88 | progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2); 89 | 90 | ProgressChanged(totalDownloadSize, totalBytesRead, progressPercentage); 91 | } 92 | 93 | public void Dispose() => _httpClient?.Dispose(); 94 | } 95 | } -------------------------------------------------------------------------------- /src/vm/base/NekoMarshal.cs: -------------------------------------------------------------------------------- 1 | namespace Neko 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Base; 7 | using NativeRing; 8 | using static NativeRing.NekoValueType; 9 | 10 | public static unsafe class NekoMarshal 11 | { 12 | internal static readonly IDictionary variants = new Dictionary(); 13 | 14 | static NekoMarshal() 15 | { 16 | variants.Add(typeof(int), VAL_INT); 17 | variants.Add(typeof(string), VAL_STRING); 18 | variants.Add(typeof(bool), VAL_BOOL); 19 | variants.Add(typeof(float), VAL_FLOAT); 20 | variants.Add(typeof(NekoFunction), VAL_FUNCTION); 21 | variants.Add(typeof(NekoObject), VAL_OBJECT); 22 | } 23 | 24 | public static T PtrToCLR(NekoValue* value) 25 | { 26 | var result = CreateInstance(value); 27 | if (result is null) 28 | return default; 29 | return (T)result; 30 | } 31 | 32 | 33 | public static NekoValue* CLRToPrt(T value) 34 | => CLRToPrt((object)value); 35 | 36 | public static NekoValue* CLRToPrt(object value) 37 | { 38 | if (value is null) 39 | return Native.v_null(); 40 | if (value is string s) 41 | return (NekoString)s; 42 | if (value is float f) 43 | return (NekoFloat)f; 44 | if (value is double d) 45 | return (NekoFloat)d; 46 | if (value is bool b) 47 | return (NekoBool)b; 48 | if (value is NekoFunction fn) 49 | return fn.@ref; 50 | if (value is NekoArray ar) 51 | return ar.@ref; 52 | if (value is NekoRuntimeObject ro) 53 | return ro.@ref; 54 | 55 | #region numbers 56 | if (value is int i32) 57 | return (NekoInt)i32; 58 | if (value is short i16) 59 | return (NekoInt)i16; 60 | if (value is ushort u16) 61 | return (NekoInt)u16; 62 | if (value is byte u8) 63 | return (NekoInt)u8; 64 | if (value is sbyte i8) 65 | return (NekoInt)i8; 66 | #endregion 67 | 68 | if (value is Delegate) 69 | throw new NotSupportedException($"temporary delegates not support"); 70 | throw new NotSupportedException($"Type {value.GetType()} is not support marshaling."); 71 | } 72 | public static NekoValueType GetNekoVariant(object o) 73 | { 74 | if (variants.ContainsKey(o.GetType())) 75 | return variants[o.GetType()]; 76 | throw new TypeIsNotSupportNekoException(o.GetType().Name); 77 | } 78 | 79 | public static Type GetCLRVariant(uint type) 80 | => GetCLRVariant((NekoValueType)type); 81 | public static Type GetCLRVariant(NekoValueType type) 82 | { 83 | if (variants.Any(x => x.Value == type)) 84 | return variants.First(x => x.Value == type).Key; 85 | throw new TypeIsNotSupportNekoException($"{type}"); 86 | } 87 | 88 | public static object CreateInstance(NekoValue* value) 89 | { 90 | if (NekoType.is_null(value)) 91 | return null; 92 | if (value == Native.v_true()) 93 | return true; 94 | if (value == Native.v_false()) 95 | return false; 96 | if (NekoType.get_valtype(value) == VAL_FUNCTION) 97 | return new NekoFunction("", value); 98 | if (Enum.IsDefined(typeof(NekoValueType), NekoType.get_valtype(value))) 99 | return NekoObject.Create(value); 100 | throw new TypeIsNotSupportNekoException($"{(NekoValueType)value->t}"); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/tools/nekoc/GithubClient.cs: -------------------------------------------------------------------------------- 1 | namespace nekoc 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | using Flurl.Http; 9 | using Konsole; 10 | using Newtonsoft.Json; 11 | 12 | public class GithubClient 13 | { 14 | private readonly string _owner; 15 | private readonly string _repo; 16 | private readonly string _version; 17 | 18 | public GithubClient(string owner, string repo, string version) 19 | { 20 | _owner = owner; 21 | _repo = repo; 22 | _version = version; 23 | } 24 | 25 | public string GetFile() 26 | => $"neko-{_version}-{AppState.GetOS()}64.{(AppState.GetOS() == "win" ? "zip" : "tar.gz")}"; 27 | 28 | public async ValueTask DownloadAsync() 29 | { 30 | var releases = await $"https://api.github.com/repos/{_owner}/{_repo}/releases" 31 | .WithHeader("User-Agent", $"NekoC .NET/{AppState.GetVersion()}") 32 | .GetJsonAsync(); 33 | var release = releases.First(); 34 | var targetFile = GetFile(); 35 | 36 | var asset = release.Assets.FirstOrDefault(x => x.Name == targetFile); 37 | 38 | if (asset is null) 39 | throw new Exception($"Failed find {targetFile} in latest release in '{_owner}/{_repo}'"); 40 | 41 | 42 | using var handler = HttpClientDownloadWithProgress.Create(asset.BrowserDownloadUrl, 43 | new FileInfo(Path.Combine(AppState.GetFolderForCache().FullName, targetFile))); 44 | Console.WriteLine($"{":page_with_curl:".Emoji()} Download {asset.BrowserDownloadUrl}.."); 45 | var pb = new ProgressBar(100, 0, '='); 46 | 47 | handler.ProgressChanged += (size, downloaded, percentage) => 48 | { 49 | if (percentage != null) 50 | pb.Refresh((int)percentage.Value, $""); 51 | }; 52 | 53 | await handler.StartDownload(); 54 | 55 | 56 | Console.WriteLine(); 57 | 58 | return new FileInfo(Path.Combine(AppState.GetFolderForCache().FullName, targetFile)); 59 | } 60 | } 61 | public class GithubRelease 62 | { 63 | [JsonProperty("tag_name")] 64 | public string TagName { get; set; } 65 | 66 | [JsonProperty("target_commitish")] 67 | public string TargetCommitish { get; set; } 68 | 69 | [JsonProperty("created_at")] 70 | public DateTimeOffset CreatedAt { get; set; } 71 | 72 | [JsonProperty("published_at")] 73 | public DateTimeOffset PublishedAt { get; set; } 74 | 75 | [JsonProperty("assets")] 76 | public List Assets { get; set; } 77 | } 78 | 79 | public class Asset 80 | { 81 | [JsonProperty("url")] 82 | public Uri Url { get; set; } 83 | 84 | [JsonProperty("id")] 85 | public long Id { get; set; } 86 | 87 | [JsonProperty("node_id")] 88 | public string NodeId { get; set; } 89 | 90 | [JsonProperty("name")] 91 | public string Name { get; set; } 92 | 93 | [JsonProperty("label")] 94 | public string Label { get; set; } 95 | 96 | [JsonProperty("content_type")] 97 | public string ContentType { get; set; } 98 | 99 | [JsonProperty("state")] 100 | public string State { get; set; } 101 | 102 | [JsonProperty("size")] 103 | public long Size { get; set; } 104 | 105 | [JsonProperty("download_count")] 106 | public long DownloadCount { get; set; } 107 | 108 | [JsonProperty("created_at")] 109 | public DateTimeOffset CreatedAt { get; set; } 110 | 111 | [JsonProperty("updated_at")] 112 | public DateTimeOffset UpdatedAt { get; set; } 113 | 114 | [JsonProperty("browser_download_url")] 115 | public string BrowserDownloadUrl { get; set; } 116 | } 117 | } -------------------------------------------------------------------------------- /src/vm/base/types/NekoFunction.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using System.Runtime.InteropServices; 5 | using NativeRing; 6 | 7 | public delegate NekoObject Invoke0(); 8 | public delegate NekoObject InvokeN(params NekoObject[] objs); 9 | 10 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 11 | public delegate void static_delegate(); 12 | public sealed unsafe class NekoFunction : NekoObject, INativeCast<_neko_function> 13 | { 14 | private NekoFunctionKind _kind; 15 | public string Name { get; } 16 | public int ArgCount { get; } 17 | 18 | public NekoFunction(string functionName, NekoValue* value) : base(value) 19 | { 20 | NekoAssert.IsFunction(value); 21 | Name = functionName; 22 | ArgCount = AsInternal()->nargs; 23 | _kind = NekoFunctionKind.Imported; 24 | } 25 | 26 | public static NekoFunction Create(static_delegate actor, string name) 27 | { 28 | // TODO check function is static 29 | var p = Marshal.GetFunctionPointerForDelegate(actor); 30 | var result = Native.neko_alloc_function((void*)p, 0, name); 31 | return new NekoFunction(name, result) { _kind = NekoFunctionKind.Exported }; 32 | } 33 | 34 | public static NekoFunction Create(NekoModule module, string functionName) 35 | { 36 | var field = Native.neko_val_field(module, Native.neko_val_id(functionName)); 37 | return new NekoFunction(functionName, field); 38 | } 39 | public NekoObject Invoke() 40 | { 41 | if (0 != ArgCount) 42 | throw new Exception(); 43 | return Native.neko_val_call0(@ref); 44 | } 45 | public NekoValue* InvokeWithNative(params NekoValue*[] args) 46 | { 47 | if (args.Length != ArgCount) 48 | throw new Exception(); 49 | if (args.Length == 0) 50 | return Native.neko_val_call0(@ref); 51 | if (args.Length == 1) 52 | return Native.neko_val_call1(@ref, args[0]); 53 | if (args.Length == 2) 54 | return Native.neko_val_call2(@ref, args[0], args[1]); 55 | if (args.Length == 3) 56 | return Native.neko_val_call3(@ref, args[0], args[1], args[3]); 57 | throw new Exception(); 58 | } 59 | 60 | public R Invoke(params object[] args) 61 | => NekoMarshal.PtrToCLR(Invoke(args).@ref); 62 | 63 | public NekoObject Invoke(params object[] args) 64 | { 65 | if (args is null) 66 | args = new object[] { null }; 67 | if (args.Length != ArgCount) 68 | throw new InvalidArgumentNekoException(); 69 | var nargs = new NekoValue*[args.Length]; 70 | for (var i = 0; i != args.Length; i++) 71 | nargs[i] = NekoMarshal.CLRToPrt(args[i]); 72 | var result = args.Length switch 73 | { 74 | 1 => Native.neko_val_call1(@ref, nargs[0]), 75 | 2 => Native.neko_val_call2(@ref, nargs[0], nargs[1]), 76 | 3 => Native.neko_val_call3(@ref, nargs[0], nargs[1], nargs[2]), 77 | _ => Native.neko_val_callN(@ref, AllocateArgs(args), args.Length) 78 | }; 79 | 80 | var obj = Create(result); 81 | 82 | if (obj is NekoRuntimeException exception) 83 | throw new NekoVMException(exception); 84 | return result; 85 | } 86 | 87 | public bool IsExported() => _kind == NekoFunctionKind.Exported; 88 | 89 | 90 | public static NekoValue** AllocateArgs(params object[] args) 91 | { 92 | var newArgs = stackalloc NekoValue*[args.Length]; 93 | for (var i = 0; i != args.Length; i++) 94 | newArgs[i] = NekoMarshal.CLRToPrt(args[i]); 95 | return newArgs; 96 | } 97 | 98 | public static implicit operator Invoke0(NekoFunction fun) => fun.Invoke; 99 | public static implicit operator InvokeN(NekoFunction fun) => fun.Invoke; 100 | 101 | 102 | public _neko_function* AsInternal() => (_neko_function*)@ref; 103 | } 104 | } -------------------------------------------------------------------------------- /src/test/vm-base-test/VMTests.cs: -------------------------------------------------------------------------------- 1 | namespace vm_base_test 2 | { 3 | using System; 4 | using System.IO; 5 | using System.Linq; 6 | using Neko.Base; 7 | using Neko.NativeRing; 8 | using NUnit.Framework; 9 | 10 | public class VMTests 11 | { 12 | private Neko vm; 13 | private NekoModule module; 14 | [OneTimeSetUp] 15 | public void Setup() 16 | { 17 | vm = new Neko(); 18 | module = vm.LoadModule(new FileInfo("./unit.n")); 19 | } 20 | 21 | [OneTimeTearDown] 22 | public void Shutdown() 23 | => (vm as IDisposable).Dispose(); 24 | 25 | [Test] 26 | public void TestObjectType() 27 | { 28 | var obj = module["testObject"].Invoke(); 29 | Assert.IsInstanceOf(obj); 30 | } 31 | 32 | [Test] 33 | public void TestLenFields() 34 | { 35 | var robj = module["testObject"].Invoke() as NekoRuntimeObject; 36 | Assert.NotNull(robj); 37 | Assert.AreEqual(4, robj.GetFields().Length); 38 | } 39 | [Test] 40 | public unsafe void TestFields() 41 | { 42 | var robj = module["testObject"].Invoke() as NekoRuntimeObject; 43 | Assert.NotNull(robj); 44 | Assert.AreEqual( 45 | new[] { "x", "y", "text", "fn" }.OrderBy(x => x), 46 | robj.GetFields().OrderBy(x => x)); 47 | } 48 | [Test] 49 | public unsafe void TestObjectValueInt() 50 | { 51 | var robj = module["testObject"].Invoke() as NekoRuntimeObject; 52 | Assert.NotNull(robj); 53 | Assert.AreEqual(-1, (int)robj.AsDynamic().y); 54 | } 55 | [Test] 56 | public void TestObjectValueString() 57 | { 58 | var robj = module["testObject"].Invoke() as NekoRuntimeObject; 59 | Assert.NotNull(robj); 60 | Assert.AreEqual("the text", (string)robj.AsDynamic().text); 61 | } 62 | [Test] 63 | public void CallAndGetInt() 64 | { 65 | var o = module["setget_int"].Invoke(1); 66 | Assert.NotNull(o); 67 | Assert.AreEqual(1, (int)(NekoInt)o); 68 | } 69 | [Test] 70 | public void CallAndGetFloat() 71 | { 72 | var o = module["setget_float"].Invoke(14.4f); 73 | Assert.NotNull(o); 74 | Assert.IsNotInstanceOf(o); 75 | Assert.AreEqual(14.4f, (float)o); 76 | } 77 | [Test] 78 | public void CallAndGetString() 79 | { 80 | var o = module["setget_string"].Invoke("foo"); 81 | Assert.NotNull(o); 82 | Assert.AreEqual("foo", (string)(NekoString)o); 83 | } 84 | [Test] 85 | public void CallAndGetBool() 86 | { 87 | var o = module["setget_boolean"].Invoke(true); 88 | Assert.NotNull(o); 89 | Assert.AreEqual(true, (bool)(NekoBool)o); 90 | o = module["setget_boolean"].Invoke(false); 91 | Assert.AreEqual(false, (bool)(NekoBool)o); 92 | } 93 | [Test] 94 | public void CallRefFunction() 95 | { 96 | var f = NekoFunction.Create(Success, nameof(Success)); 97 | module["getset_and_call_function"].Invoke(f); 98 | } 99 | 100 | public static void Success() => Assert.Pass(); 101 | 102 | //[Test] 103 | public void CallAndGetArray() 104 | { 105 | var arr = NekoArray.Alloc(3); 106 | arr[0] = true; 107 | arr[1] = false; 108 | arr[2] = "test"; 109 | 110 | var result = module["setget_array"].Invoke(arr); 111 | Assert.NotNull(result); 112 | Assert.IsNotInstanceOf(result); 113 | Assert.IsInstanceOf(result); 114 | var result_array = (NekoArray)result; 115 | 116 | Assert.AreEqual(3, result_array.Count); 117 | Assert.AreEqual(true, (bool)result_array.First()); 118 | } 119 | [Test] 120 | public void GetArray() 121 | { 122 | var result = module["new_array"].Invoke(); 123 | Assert.NotNull(result); 124 | Assert.IsNotInstanceOf(result); 125 | Assert.IsInstanceOf(result); 126 | var result_array = (NekoArray)result; 127 | Assert.AreEqual(4, result_array.Count); 128 | Assert.AreEqual("1", (string)result_array[0]); 129 | Assert.AreEqual(2.12f, (float)result_array[1]); 130 | Assert.AreEqual("test", (string)result_array[2]); 131 | Assert.AreEqual(true, (bool)result_array[3]); 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /src/vm/base/Neko.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.Base 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Runtime.InteropServices; 9 | using System.Threading; 10 | using NativeRing; 11 | using static NativeRing.Native; 12 | 13 | public unsafe class Neko : INekoDisposable, INativeCast<_neko_vm> 14 | { 15 | internal NekoVM* _vm; 16 | internal readonly IDictionary modules = new Dictionary(); 17 | internal NekoLoader _loader { get; private set; } 18 | public int ThreadID { get; internal set; } 19 | internal NekoGlobal Global { get; } 20 | public Neko() 21 | { 22 | ThreadID = Thread.CurrentThread.ManagedThreadId; 23 | neko_global_init(); 24 | _vm = neko_vm_alloc(IntPtr.Zero.ToPointer()); 25 | neko_vm_select(_vm); 26 | _loader = NekoLoader.CreateDefault(); 27 | Global = new NekoGlobal(get_neko_builtins()[0]); 28 | } 29 | 30 | public NekoModule LoadModule(string path) 31 | { 32 | var file = new FileInfo(path); 33 | if (!file.Exists) 34 | throw new Exception($"File '{path}' not exists."); 35 | return LoadModule(file); 36 | } 37 | public NekoModule LoadModule(FileInfo file) 38 | { 39 | GuardBarrier(); 40 | var result = _loader.Load(file); 41 | modules.Add(file.Name, result); 42 | return result; 43 | } 44 | public void GuardBarrier() 45 | { 46 | ThreadID = Thread.CurrentThread.ManagedThreadId; 47 | neko_vm_select(_vm); 48 | } 49 | 50 | 51 | 52 | 53 | public void MarshalGlobal(Type t) 54 | { 55 | if (!t.IsClass) 56 | throw new ArgumentException($"'{t.Name}' is not class."); 57 | if (!(t.IsAbstract && t.IsSealed)) 58 | throw new ArgumentException($"'{t.Name}' is not static class."); 59 | 60 | GuardBarrier(); 61 | 62 | var methods = t.GetMethods(BindingFlags.Public | BindingFlags.Static); 63 | var gen = get_neko_builtins(); 64 | foreach (var info in methods) 65 | { 66 | var @params = info.GetParameters(); 67 | if (@params.Length > 5) 68 | continue; 69 | if (!@params.All(x => NekoType.IsCompatible(x))) 70 | continue; 71 | if (!(info.ReturnType == typeof(void) || NekoType.IsCompatible(info.ReturnType))) 72 | continue; 73 | var m = MakeNekoProxy(info); 74 | var f = neko_alloc_function((void*)MakeNekoProxy(info), (uint)@params.Length, $"${info.Name}"); 75 | neko_alloc_field(gen[0], neko_val_id(info.Name), f); 76 | } 77 | } 78 | 79 | internal unsafe static nint MakeNekoProxy(MethodInfo method) 80 | { 81 | var @p = method.GetParameters(); 82 | var f = method.ReturnType == typeof(void); 83 | 84 | static nint Link(Delegate d) where D : Delegate 85 | => Marshal.GetFunctionPointerForDelegate((D)d); 86 | 87 | unsafe static oic GetOpImplicit() 88 | => typeof(NekoObject).GetMethod("op_Implicit", new[] { typeof(NekoValue*) }).CreateDelegate(); 89 | 90 | unsafe static object[] Populate(ParameterInfo[] args, params void*[] innerArgs) 91 | => args.Select((x, i) => GetOpImplicit()((NekoValue*)innerArgs[i])).ToArray(); 92 | 93 | // maybe this need refactoring(((9(9 94 | return @p.Length switch 95 | { 96 | 0 when f => Link((nad0)(() => __unsafe_cast._cmv(method))), 97 | 1 when f => Link((nad1)((v1) => __unsafe_cast._cmv(method, Populate(@p, v1)))), 98 | 2 when f => Link((nad2)((v1, v2) => __unsafe_cast._cmv(method, Populate(@p, v1, v2)))), 99 | 3 when f => Link((nad3)((v1, v2, v3) => __unsafe_cast._cmv(method, Populate(@p, v1, v2, v3)))), 100 | 4 when f => Link((nad4)((v1, v2, v3, v4) => __unsafe_cast._cmv(method, Populate(@p, v1, v2, v3, v4)))), 101 | 5 when f => Link((nad5)((v1, v2, v3, v4, v5) => __unsafe_cast._cmv(method, Populate(@p, v1, v2, v3, v4, v5)))), 102 | 103 | 0 when !f => Link((nfd0)(() => __unsafe_cast._cmp(method))), 104 | 1 when !f => Link((nfd1)((v1) => __unsafe_cast._cmp(method, Populate(@p, v1)))), 105 | 2 when !f => Link((nfd2)((v1, v2) => __unsafe_cast._cmp(method, Populate(@p, v1, v2)))), 106 | 3 when !f => Link((nfd3)((v1, v2, v3) => __unsafe_cast._cmp(method, Populate(@p, v1, v2, v3)))), 107 | 4 when !f => Link((nfd4)((v1, v2, v3, v4) => __unsafe_cast._cmp(method, Populate(@p, v1, v2, v3, v4)))), 108 | 5 when !f => Link((nfd5)((v1, v2, v3, v4, v5) => __unsafe_cast._cmp(method, Populate(@p, v1, v2, v3, v4, v5)))), 109 | _ => throw new NotSupportedException("Params count too many. [p > 5]") 110 | }; 111 | } 112 | 113 | void INekoDisposable._release() 114 | { 115 | GuardBarrier(); 116 | neko_vm_select(null); 117 | _vm = null; 118 | _loader = null; 119 | foreach (var (_, module) in modules) 120 | (module as IDisposable).Dispose(); 121 | neko_global_free(); 122 | } 123 | 124 | public _neko_vm* AsInternal() => (_neko_vm*)_vm; 125 | ~Neko() => (this as INekoDisposable)._release(); 126 | } 127 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | 352 | compiller/ 353 | -------------------------------------------------------------------------------- /src/tools/nekoc/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using Pastel; 10 | using System.IO.Compression; 11 | using Mono.Unix.Native; 12 | using MoreLinq; 13 | using nekoc; 14 | using SharpCompress.Archives.Tar; 15 | using SharpCompress.Readers; 16 | using static System.Console; 17 | using static System.Environment; 18 | using static System.IO.Path; 19 | using static nekoc.AppState; 20 | 21 | public static class Input 22 | { 23 | public static async Task Main(string[] args) 24 | { 25 | const string NEKO_C_VERSION = "2.3.0"; 26 | 27 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 28 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 29 | OutputEncoding = Encoding.Unicode; 30 | PopArgs(ref args, "--trace", ref isTrace); 31 | PopArgs(ref args, "--force-install", ref forceInstall); 32 | 33 | if (isTrace) 34 | trace("trace log enabled"); 35 | if (forceInstall) 36 | trace("force installing enabled"); 37 | 38 | PrintHeader(); 39 | 40 | if (GetOS() == "osx") 41 | { 42 | warn($"Please note that the tool may not work correctly under the OSX operating system.".Pastel(Color.Orange)); 43 | warn($"If you find a problem, report it to the repository.".Pastel(Color.Orange)); 44 | } 45 | 46 | var compilerFile = await GetOrCreateCompilerAsync(); 47 | 48 | if (args is { Length: 0 }) 49 | return await ExecAsync(compilerFile, "--help", "-v"); 50 | return await ExecAsync(compilerFile, args.Concat(new[] { "-v" }).ToArray()); 51 | 52 | 53 | 54 | 55 | static FileInfo GetCompilerBinariesFile() 56 | { 57 | var cache = GetFolderForCache(); 58 | if (!cache.Exists) 59 | Directory.CreateDirectory(cache.FullName); 60 | return new(Combine(cache.FullName, $"nekoc{(GetOS() == "win" ? ".exe" : "")}")); 61 | } 62 | 63 | async Task GetOrCreateCompilerAsync() 64 | { 65 | var extractor = default(Action); 66 | var cache = GetFolderForCache(); 67 | if (forceInstall && cache.Exists) 68 | { 69 | warn($"forceInstall && cache.Exists"); 70 | cache.EnumerateFiles("*.*").Pipe(x => x.Delete()).Pipe(x => trace($"delete '{x}'..")).Consume(); 71 | cache.EnumerateDirectories().Pipe(x => x.Delete()).Pipe(x => trace($"delete '{x}'..")).Consume(); 72 | } 73 | var c_binary = GetCompilerBinariesFile(); 74 | trace($"lookup compiler binary file..."); 75 | if (c_binary.Exists) 76 | { 77 | trace($"exists..."); 78 | return c_binary; 79 | } 80 | trace($"not exists... download from github..."); 81 | var zip = await new GithubClient("HaxeFoundation", "neko", NEKO_C_VERSION).DownloadAsync(); 82 | if (GetOS() == "win") extractor = (s) => 83 | { 84 | trace($"extraction '{zip.FullName}' archive..."); 85 | ZipFile.ExtractToDirectory(zip.FullName, s); 86 | var dir = zip.FullName.Replace(".zip", "").AsDirectoryInfo(); 87 | dir.EnumerateFiles() 88 | .Pipe(x => File.Move(x.FullName, Combine(s, GetFileName(x.FullName)), true)) 89 | .Pipe(x => trace($"move '{x}'")) 90 | .Consume(); 91 | }; 92 | else extractor = (s) => 93 | { 94 | using var file = File.OpenRead(zip.FullName); 95 | using var tar = TarArchive.Open(file); 96 | using var reader = tar.ExtractAllEntries(); 97 | trace($"extraction '{zip.FullName}' archive..."); 98 | reader.WriteAllToDirectory(s); 99 | 100 | // Could not write symlink 101 | // for more information please see https://github.com/dotnet/runtime/issues/24271 102 | trace($"create 'libneko.so.{NEKO_C_VERSION}'->'libneko.so.{NEKO_C_VERSION[0]}'"); 103 | File.Copy(Combine(s, $"libneko.so.{NEKO_C_VERSION}"), Combine(s, $"libneko.so.{NEKO_C_VERSION[0]}")); 104 | trace($"create 'libneko.so.{NEKO_C_VERSION}'->'libneko.so'"); 105 | File.Copy(Combine(s, $"libneko.so.{NEKO_C_VERSION}"), Combine(s, $"libneko.so")); 106 | trace("population binary variation has success"); 107 | trace($"chmod :: {FilePermissions.ACCESSPERMS} -> '{c_binary.FullName}'"); 108 | Syscall.chmod(c_binary.FullName, FilePermissions.ACCESSPERMS); 109 | }; 110 | extractor(GetFolderForCache().FullName); 111 | 112 | return c_binary; 113 | } 114 | 115 | void PrintHeader() 116 | { 117 | if (GetEnvironmentVariable("WT_SESSION") == null && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 118 | { 119 | trace("disable coloring and emoji..."); 120 | SetEnvironmentVariable($"NO_COLOR", "true"); 121 | SetEnvironmentVariable($"EMOJI_USE", "0"); 122 | return; 123 | } 124 | WriteLine($"⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⡀⢳⣤⡙⠻⢿⣿⣿⣿⠿⢿⣿⣿⠿⢿⣿⣿⣿⠿⠛⣡⣴⠇⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⣧⠸⡀⡙⢶⣤⣈⣁⣤⣤⠀⠹⠃⢴⣶⣤⣭⣤⡶⢋⡁⡜⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⣿⣆⢻⡼⣷⡍⠉⠁⠀⣹⣆⠀⢀⣿⡁⠀⠉⠉⣴⡏⣼⢃⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⣿⡿⢀⠇⠉⠀⠀⠀⠘⠛⢻⣦⡾⠛⠋⠀⠀⠀⠈⠁⣧⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⡿⢁⡞⠀⠀⣴⡶⠦⣄⡀⠿⣿⡿⠂⣠⠴⠶⣶⡀⠀⠸⣧⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⠃⣼⢀⣤⣶⣿⣿⣶⣶⣿⣶⣿⣷⣿⣷⣶⣾⣿⣶⣤⡀⢹⡆⢿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣿⡿⢿⣿⣿⡿⠿⠿⠿⠿⠿⣿⣿⣿⠿⣿⣿⣿⠿⢿⣿⣿⡿⠿⠿⠿⠿⠿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⢰⠃⣠⣿⣿⠿⠿⠟⠿⢿⡇⠀⠀⣹⠿⠛⠛⠻⠿⢿⣇⠈⢷⢸⣿⣿⣿⣿⣿⣿⡇⢠⣄⠙⢿⡇⢸⣿⣿⡗⠒⠒⠒⠒⠒⣿⣿⣿⠀⠛⠛⠃⠐⢻⣿⣿⡇⢰⣶⣶⣶⠀⣿⣿⣿⣿⣿\r\n⣿⣿⡏⢸⡾⠛⢉⣤⣤⣄⠀⠶⠿⠟⠀⠘⠛⠿⠶⢀⣤⣤⣀⠈⠳⣾⠀⣿⣿⣿⣿⣿⣿⣇⣸⣿⣷⣤⣀⣸⣿⣿⣏⣉⣉⣉⣉⣉⣿⣿⣿⣀⣿⣿⣿⣇⣸⣿⣿⣇⣈⣉⣉⣉⣀⣿⣿⣿⣿⣿\r\n⣿⣿⡇⠈⠀⣼⠟⠿⣿⣿⣿⣶⠀⢰⠀⢠⡆⢰⣾⣿⣿⡿⠟⢿⣆⠈⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣇⠀⢰⣏⣴⡾⠟⠛⠛⠛⣇⢸⣿⣿⢇⡟⠛⠛⠛⠿⢷⣄⣿⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⣧⠀⠟⠁⣤⣾⣿⣿⣧⠸⣾⣭⣽⣾⢠⣿⣿⣿⣶⣄⠙⠏⢠⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⣿⣧⠀⣾⣿⣿⣿⣿⣿⣆⠙⠿⠿⢃⣼⣿⣿⣿⣿⣿⡆⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\r\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿" 125 | .Pastel(Color.MediumPurple)); 126 | WriteLine(); 127 | } 128 | static void PopArgs(ref string[] args, string arg, ref bool target) 129 | { 130 | if (target = args.Contains(arg)) 131 | args = args.Where(x => x != arg).ToArray(); 132 | } 133 | async Task ExecAsync(FileInfo compiler, params string[] args) 134 | { 135 | trace($"call {nameof(ExecAsync)} -> {compiler} and {string.Join(',', args)}"); 136 | var inf = new ProcessStartInfo(compiler.FullName, string.Join(' ', args)); 137 | inf.WorkingDirectory = Directory.GetCurrentDirectory(); 138 | trace($"working directory '{inf.WorkingDirectory}'"); 139 | var proc = Process.Start(inf); 140 | await proc.WaitForExitAsync(); 141 | trace($"process '{compiler}' has complete execution with {proc.ExitCode} exit code"); 142 | if (proc.ExitCode == 0) 143 | trace($"success".Pastel(Color.GreenYellow)); 144 | else 145 | error($"exit code {proc.ExitCode}".Pastel(Color.Red)); 146 | return proc.ExitCode; 147 | } 148 | 149 | void trace(string s) => WriteLine($"[{"neko".Pastel(Color.Purple)}][{"T".Pastel(Color.Gray)}]: {s}"); 150 | void error(string s) => WriteLine($"[{"neko".Pastel(Color.Purple)}][{"E".Pastel(Color.Red)}]: {s}"); 151 | void warn(string s) => WriteLine($"[{"neko".Pastel(Color.Purple)}][{"W".Pastel(Color.Orange)}]: {s}"); 152 | } 153 | } -------------------------------------------------------------------------------- /src/vm/native/Native.cs: -------------------------------------------------------------------------------- 1 | namespace Neko.NativeRing 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Runtime.InteropServices; 9 | using Base; 10 | 11 | internal static unsafe class Native 12 | { 13 | private static IntPtr _ref; 14 | private static bool isDebug; 15 | private static NekoValue Null = new NekoValue { t = (uint)NekoValueType.VAL_NULL }; 16 | 17 | internal static IntPtr libRef 18 | { 19 | get 20 | { 21 | if (_ref == IntPtr.Zero) 22 | return (_ref = NativeLibrary.Load("neko")); 23 | return _ref; 24 | } 25 | set => _ref = value; 26 | } 27 | static Native() 28 | { 29 | isDebug = Environment.GetEnvironmentVariable("LD_DEBUG") == "libs"; 30 | if (RuntimeInformation.ProcessArchitecture != Architecture.X64) 31 | throw new NotSupportedException($"Temporary support only x64 os arch."); 32 | NativeLibrary.SetDllImportResolver(typeof(Native).Assembly, Resolver); 33 | __debug_loader(".ctor"); 34 | } 35 | 36 | private static void __debug_loader(string s) 37 | { 38 | if (!isDebug) 39 | return; 40 | lock (Console.Out) 41 | { 42 | Console.ForegroundColor = ConsoleColor.Red; 43 | Console.WriteLine($"neko::native{s}"); 44 | Console.ForegroundColor = ConsoleColor.White; 45 | } 46 | } 47 | 48 | private static IntPtr Resolver(string name, Assembly asm, DllImportSearchPath? search) 49 | { 50 | if (name.Equals("neko", StringComparison.InvariantCultureIgnoreCase)) 51 | { 52 | if (_ref == IntPtr.Zero) 53 | return _ref = _resolver(name); 54 | return _ref; 55 | } 56 | return _resolver(name); 57 | } 58 | 59 | private static string[] _getSearchPath() => 60 | new[] 61 | { 62 | "./{__formatted_lib_name__}", 63 | "./runtimes/{__OS__}-x64/native/{__formatted_lib_name__}", 64 | "./bin64/{__formatted_lib_name__}", 65 | "./Engine64/{__formatted_lib_name__}", 66 | "{__formatted_lib_name__}" // maybe needed load it first-shot from [/usr/lib, /windows]? 67 | }; 68 | 69 | private static IntPtr _resolver(string name) 70 | { 71 | var paths = _getSearchPath() 72 | .Select(x => x.Replace("{__formatted_lib_name__}", _format_lib(name))) 73 | .Select(x => x.Replace("{__OS__}", _get_os())) 74 | .Pipe(x => __debug_loader($".find_path {x}")) 75 | .ToArray(); 76 | var targetPath = paths.Select 77 | (path => (path, NativeLibrary.TryLoad(path, out _))) 78 | .Pipe(x => __debug_loader($".try_find in {x.path} -> {x.result}")) 79 | .Where(x => x.result) 80 | .FirstOrDefault().path ?? name; 81 | return NativeLibrary.Load(targetPath); 82 | } 83 | 84 | private static string _format_lib(string name) 85 | { 86 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 87 | return $"{name}.dll"; 88 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 89 | return $"lib{name}.so"; 90 | if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 91 | return $"{name}.dylib"; 92 | throw new NotSupportedException(); 93 | } 94 | private static string _get_os() 95 | { 96 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 97 | return "win"; 98 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 99 | return "linux"; 100 | if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 101 | return "osx"; 102 | throw new NotSupportedException(); 103 | } 104 | 105 | [DllImport("neko")] 106 | public static extern void neko_global_init(); 107 | [DllImport("neko")] 108 | public static extern void neko_global_free(); 109 | [DllImport("neko")] 110 | public static extern void neko_gc_major(); 111 | [DllImport("neko")] 112 | public static extern void neko_gc_loop(); 113 | [DllImport("neko")] 114 | public static extern NekoVM* neko_vm_alloc(void* _); 115 | [DllImport("neko")] 116 | public static extern void neko_vm_select(NekoVM* @ref); 117 | [DllImport("neko")] 118 | public static extern NekoValue* neko_default_loader(char** argv, int argc); 119 | [DllImport("neko")] 120 | public static extern NekoValue* neko_val_callEx( 121 | NekoValue* @this, 122 | NekoValue* v, 123 | NekoValue** args, 124 | int nargs, 125 | ref NekoValue* exc); 126 | [DllImport("neko", CharSet = CharSet.Ansi)] 127 | public static extern int neko_val_id(string s); 128 | [DllImport("neko", CharSet = CharSet.Ansi)] 129 | public static extern NekoValue* neko_alloc_string(string str); 130 | [DllImport("neko")] 131 | public static extern NekoValue* neko_val_field(NekoValue* o, int f); 132 | [DllImport("neko")] 133 | public static extern NekoValue** neko_alloc_root(int gen); 134 | [DllImport("neko")] 135 | public static extern NekoBuffer* neko_alloc_buffer(void* chars); 136 | [DllImport("neko")] 137 | public static extern void neko_val_buffer(NekoBuffer* buffer, NekoValue* value); 138 | [DllImport("neko")] 139 | public static extern NekoValue* neko_buffer_to_string(NekoBuffer* buffer); 140 | 141 | public static NekoValue* v_null() 142 | { 143 | fixed (NekoValue* p = &Null) 144 | return p; 145 | } 146 | [DllImport("neko", EntryPoint = "get_value_true")] 147 | public static extern NekoValue* v_true(); 148 | [DllImport("neko", EntryPoint = "get_value_false")] 149 | public static extern NekoValue* v_false(); 150 | [DllImport("neko")] 151 | public static extern NekoValue** get_neko_builtins(); 152 | 153 | 154 | 155 | [DllImport("neko")] 156 | public static extern NekoValue* neko_val_call0(NekoValue* function); 157 | [DllImport("neko")] 158 | public static extern NekoValue* neko_val_call1(NekoValue* function, NekoValue* v1); 159 | [DllImport("neko")] 160 | public static extern NekoValue* neko_val_call2(NekoValue* function, NekoValue* v1, NekoValue* v2); 161 | [DllImport("neko")] 162 | public static extern NekoValue* neko_val_call3(NekoValue* function, NekoValue* v1, NekoValue* v2, NekoValue* v3); 163 | [DllImport("neko")] 164 | public static extern NekoValue* neko_val_callN(NekoValue* function, NekoValue** args, int nargs); 165 | 166 | [DllImport("neko")] 167 | public static extern int neko_val_hash(NekoValue* value); 168 | [DllImport("neko")] 169 | public static extern NekoValue* neko_val_field_name(int field); 170 | 171 | 172 | [DllImport("neko")] 173 | public static extern NekoValue* neko_alloc_object(NekoValue* value); 174 | [DllImport("neko")] 175 | public static extern void neko_alloc_field(NekoValue* obj, int f, NekoValue* value); 176 | [DllImport("neko", CharSet = CharSet.Ansi)] 177 | public static extern NekoValue* neko_alloc_function(void* c_prim, uint args, string name); 178 | public static NekoValue* neko_alloc_bool(bool b) => b ? v_true() : v_false(); 179 | public static NekoValue* neko_alloc_int(int v) => (NekoValue*)(IntPtr)((v << 1) | 1); 180 | 181 | [DllImport("neko")] 182 | public static extern NekoValue* neko_alloc_float(double value); 183 | 184 | [DllImport("neko")] 185 | public static extern NekoValue* neko_alloc_array(uint size); 186 | public static int neko_val_array_size(NekoArray v) 187 | => (int)((uint)NekoType.tag(v.@ref) >> 4); 188 | } 189 | 190 | 191 | internal static class __linq 192 | { 193 | public static IEnumerable Pipe(this IEnumerable @this, Action selector) 194 | { 195 | foreach (var value in @this) 196 | { 197 | selector(value); 198 | yield return value; 199 | } 200 | } 201 | } 202 | } -------------------------------------------------------------------------------- /include/neko.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C)2005-2017 Haxe Foundation 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | #ifndef _NEKO_H 23 | #define _NEKO_H 24 | 25 | // OS FLAGS 26 | #if defined(_WIN32) 27 | # define NEKO_WINDOWS 28 | #endif 29 | 30 | #if defined(__APPLE__) || defined(macintosh) 31 | # define NEKO_MAC 32 | #endif 33 | 34 | #if defined(linux) || defined(__linux__) 35 | # define NEKO_LINUX 36 | #endif 37 | 38 | #if defined(__FreeBSD_kernel__) 39 | # define NEKO_GNUKBSD 40 | #endif 41 | 42 | #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 43 | # define NEKO_BSD 44 | #endif 45 | 46 | #if defined(__GNU__) 47 | # define NEKO_HURD 48 | #endif 49 | 50 | // COMPILER/PROCESSOR FLAGS 51 | #if defined(__GNUC__) 52 | # define NEKO_GCC 53 | #endif 54 | 55 | #if defined(_MSC_VER) 56 | # define NEKO_VCC 57 | // remove deprecated C API usage warnings 58 | # pragma warning( disable : 4996 ) 59 | #endif 60 | 61 | #if defined(__MINGW32__) 62 | # define NEKO_MINGW 63 | #endif 64 | 65 | #if defined(__CYGWIN__) 66 | # define NEKO_CYGWIN 67 | #endif 68 | 69 | #if defined(__i386__) || defined(_WIN32) 70 | # define NEKO_X86 71 | #endif 72 | 73 | #if defined(__ppc__) 74 | # define NEKO_PPC 75 | #endif 76 | 77 | #if defined(_64BITS) || defined(__x86_64__) 78 | # define NEKO_64BITS 79 | #endif 80 | 81 | #if defined(NEKO_LINUX) || defined(NEKO_MAC) || defined(NEKO_BSD) || defined(NEKO_GNUKBSD) || defined(NEKO_HURD) || defined(NEKO_CYGWIN) 82 | # define NEKO_POSIX 83 | #endif 84 | 85 | #if defined(NEKO_GCC) 86 | # define NEKO_THREADED 87 | # define NEKO_DIRECT_THREADED 88 | #endif 89 | 90 | #ifndef NEKO_NO_THREADS 91 | # define NEKO_THREADS 92 | #endif 93 | 94 | #include 95 | #ifndef NEKO_VCC 96 | # include 97 | #endif 98 | 99 | /* #undef NEKO_XLOCALE_H */ 100 | 101 | /* #undef NEKO_BIG_ENDIAN */ 102 | 103 | #ifndef NEKO_BIG_ENDIAN 104 | # define NEKO_LITTLE_ENDIAN 105 | #endif 106 | 107 | /* #undef NEKO_JIT_DISABLE */ 108 | /* #undef NEKO_JIT_DEBUG */ 109 | 110 | #if !defined(NEKO_JIT_DISABLE) && defined(NEKO_X86) && !defined(NEKO_MAC) && !defined(_WIN64) 111 | #define NEKO_JIT_ENABLE 112 | #endif 113 | 114 | #define NEKO_VERSION_MAJOR 2 115 | #define NEKO_VERSION_MINOR 3 116 | #define NEKO_VERSION_PATCH 0 117 | #define NEKO_VERSION 230 118 | 119 | #define NEKO_MODULE_PATH "C:/HaxeToolkit/neko" 120 | 121 | typedef intptr_t int_val; 122 | 123 | typedef enum { 124 | VAL_INT = 0xFF, 125 | VAL_NULL = 0, 126 | VAL_FLOAT = 1, 127 | VAL_BOOL = 2, 128 | VAL_STRING = 3, 129 | VAL_OBJECT = 4, 130 | VAL_ARRAY = 5, 131 | VAL_FUNCTION = 6, 132 | VAL_ABSTRACT = 7, 133 | VAL_INT32 = 8, 134 | VAL_PRIMITIVE = 6 | 16, 135 | VAL_JITFUN = 6 | 32, 136 | VAL_32_BITS = 0xFFFFFFFF 137 | } val_type; 138 | 139 | struct _value { 140 | val_type t; 141 | }; 142 | 143 | struct _buffer; 144 | typedef int field; 145 | typedef struct { int __zero; } *vkind; 146 | typedef struct _value *value; 147 | 148 | typedef struct { 149 | field id; 150 | value v; 151 | } objcell; 152 | 153 | typedef struct _objtable 154 | { 155 | int count; 156 | objcell *cells; 157 | } objtable; 158 | 159 | typedef struct _buffer *buffer; 160 | typedef double tfloat; 161 | 162 | typedef void (*finalizer)(value v); 163 | 164 | #pragma pack(4) 165 | typedef struct { 166 | val_type t; 167 | tfloat f; 168 | } vfloat; 169 | 170 | typedef struct { 171 | val_type t; 172 | int i; 173 | } vint32; 174 | #pragma pack() 175 | 176 | typedef struct _vobject { 177 | val_type t; 178 | objtable table; 179 | struct _vobject *proto; 180 | } vobject; 181 | 182 | typedef struct { 183 | val_type t; 184 | int nargs; 185 | void *addr; 186 | value env; 187 | void *module; 188 | } vfunction; 189 | 190 | typedef struct { 191 | val_type t; 192 | char c; 193 | } vstring; 194 | 195 | typedef struct { 196 | val_type t; 197 | value ptr; 198 | } varray; 199 | 200 | typedef struct { 201 | val_type t; 202 | vkind kind; 203 | void *data; 204 | } vabstract; 205 | 206 | typedef struct hcell { 207 | int hkey; 208 | value key; 209 | value val; 210 | struct hcell *next; 211 | } hcell; 212 | 213 | typedef struct { 214 | hcell **cells; 215 | int ncells; 216 | int nitems; 217 | } vhash; 218 | 219 | struct _mt_local; 220 | struct _mt_lock; 221 | typedef struct _mt_local mt_local; 222 | typedef struct _mt_lock mt_lock; 223 | 224 | #define NEKO_TAG_BITS 4 225 | 226 | #define val_tag(v) (*(val_type*)(v)) 227 | #define val_short_tag(v) (val_tag(v)&((1<data 245 | #define val_kind(v) ((vabstract*)(v))->kind 246 | 247 | #define val_type(v) (val_is_int(v) ? VAL_INT : val_short_tag(v)) 248 | #define val_int(v) (((int)(int_val)(v)) >> 1) 249 | #define val_float(v) (CONV_FLOAT ((vfloat*)(v))->f) 250 | #define val_int32(v) (((vint32*)(v))->i) 251 | #define val_any_int(v) (val_is_int(v)?val_int(v):val_int32(v)) 252 | #define val_bool(v) ((v) == val_true) 253 | #define val_number(v) (val_is_int(v)?val_int(v):((val_tag(v)==VAL_FLOAT)?val_float(v):val_int32(v))) 254 | #define val_hdata(v) ((vhash*)val_data(v)) 255 | #define val_string(v) (&((vstring*)(v))->c) 256 | #define val_strlen(v) ((signed)(((unsigned)val_tag(v)) >> NEKO_TAG_BITS)) 257 | #define val_set_length(v,l) val_tag(v) = val_short_tag(v) | ((l) << NEKO_TAG_BITS) 258 | #define val_set_size val_set_length 259 | 260 | #define val_array_size(v) ((signed)(((unsigned)val_tag(v)) >> NEKO_TAG_BITS)) 261 | #define val_array_ptr(v) (&((varray*)(v))->ptr) 262 | #define val_fun_nargs(v) ((vfunction*)(v))->nargs 263 | #define alloc_int(v) ((value)(int_val)((((int)(v)) << 1) | 1)) 264 | #define alloc_bool(b) ((b)?val_true:val_false) 265 | 266 | #define max_array_size ((1 << (32 - NEKO_TAG_BITS)) - 1) 267 | #define max_string_size ((1 << (32 - NEKO_TAG_BITS)) - 1) 268 | #define invalid_comparison 0xFE 269 | 270 | #undef EXTERN 271 | #undef EXPORT 272 | #undef IMPORT 273 | #if defined(NEKO_VCC) || defined(NEKO_MINGW) 274 | # define INLINE __inline 275 | # define EXPORT __declspec( dllexport ) 276 | # define IMPORT __declspec( dllimport ) 277 | #else 278 | # define INLINE inline 279 | # define EXPORT 280 | # define IMPORT 281 | #endif 282 | 283 | #if defined(NEKO_SOURCES) || defined(NEKO_STANDALONE) 284 | # define EXTERN EXPORT 285 | #else 286 | # define EXTERN IMPORT 287 | #endif 288 | 289 | #define VEXTERN extern EXTERN 290 | 291 | #ifdef __cplusplus 292 | # define C_FUNCTION_BEGIN extern "C" { 293 | # define C_FUNCTION_END }; 294 | #else 295 | # define C_FUNCTION_BEGIN 296 | # define C_FUNCTION_END 297 | # ifndef true 298 | # define true 1 299 | # define false 0 300 | typedef int bool; 301 | # endif 302 | #endif 303 | 304 | // the two upper bits must be either 00 or 11 305 | #define need_32_bits(i) ( (((unsigned int)(i)) + 0x40000000) & 0x80000000 ) 306 | #define alloc_best_int(i) (need_32_bits(i) ? alloc_int32(i) : alloc_int(i)) 307 | 308 | #define neko_error() return NULL 309 | #define failure(msg) _neko_failure(alloc_string(msg),__FILE__,__LINE__) 310 | #define bfailure(buf) _neko_failure(buffer_to_string(buf),__FILE__,__LINE__) 311 | 312 | #ifndef CONV_FLOAT 313 | # define CONV_FLOAT 314 | #endif 315 | 316 | #ifdef NEKO_POSIX 317 | # include 318 | # define POSIX_LABEL(name) name: 319 | # define HANDLE_EINTR(label) if( errno == EINTR ) goto label 320 | # define HANDLE_FINTR(f,label) if( ferror(f) && errno == EINTR ) goto label 321 | #else 322 | # define POSIX_LABEL(name) 323 | # define HANDLE_EINTR(label) 324 | # define HANDLE_FINTR(f,label) 325 | #endif 326 | 327 | #define VAR_ARGS (-1) 328 | #define DEFINE_PRIM_MULT(func) C_FUNCTION_BEGIN EXPORT void *func##__MULT() { return (void*)(&func); } C_FUNCTION_END 329 | #define DEFINE_PRIM(func,nargs) C_FUNCTION_BEGIN EXPORT void *func##__##nargs() { return (void*)(&func); } C_FUNCTION_END 330 | #define DEFINE_PRIM_WITH_NAME(func,name,nargs) C_FUNCTION_BEGIN EXPORT void *name##__##nargs() { return (void*)(&func); } C_FUNCTION_END 331 | #define DEFINE_KIND(name) int_val __kind_##name = 0; vkind name = (vkind)&__kind_##name; 332 | 333 | #ifdef NEKO_STANDALONE 334 | # define DEFINE_ENTRY_POINT(name) 335 | #else 336 | # define DEFINE_ENTRY_POINT(name) C_FUNCTION_BEGIN void name(); EXPORT void *__neko_entry_point() { return &name; } C_FUNCTION_END 337 | #endif 338 | 339 | #ifdef HEADER_IMPORTS 340 | # define H_EXTERN IMPORT 341 | #else 342 | # define H_EXTERN EXPORT 343 | #endif 344 | 345 | #define DECLARE_PRIM(func,nargs) C_FUNCTION_BEGIN H_EXTERN void *func##__##nargs(); C_FUNCTION_END 346 | #define DECLARE_KIND(name) C_FUNCTION_BEGIN H_EXTERN extern vkind name; C_FUNCTION_END 347 | 348 | #define alloc_int32 neko_alloc_int32 349 | #define alloc_float neko_alloc_float 350 | #define alloc_string neko_alloc_string 351 | #define alloc_empty_string neko_alloc_empty_string 352 | #define copy_string neko_copy_string 353 | #define val_this neko_val_this 354 | #define val_id neko_val_id 355 | #define val_field neko_val_field 356 | #define alloc_object neko_alloc_object 357 | #define alloc_field neko_alloc_field 358 | #define alloc_array neko_alloc_array 359 | #define val_call0 neko_val_call0 360 | #define val_call1 neko_val_call1 361 | #define val_call2 neko_val_call2 362 | #define val_call3 neko_val_call3 363 | #define val_callN neko_val_callN 364 | #define val_ocall0 neko_val_ocall0 365 | #define val_ocall1 neko_val_ocall1 366 | #define val_ocall2 neko_val_ocall2 367 | #define val_ocallN neko_val_ocallN 368 | #define val_callEx neko_val_callEx 369 | #define alloc_root neko_alloc_root 370 | #define free_root neko_free_root 371 | #define alloc neko_alloc 372 | #define alloc_private neko_alloc_private 373 | #define alloc_abstract neko_alloc_abstract 374 | #define alloc_function neko_alloc_function 375 | #define alloc_buffer neko_alloc_buffer 376 | #define buffer_append neko_buffer_append 377 | #define buffer_append_sub neko_buffer_append_sub 378 | #define buffer_append_char neko_buffer_append_char 379 | #define buffer_length neko_buffer_length 380 | #define buffer_to_string neko_buffer_to_string 381 | #define val_buffer neko_val_buffer 382 | #define val_compare neko_val_compare 383 | #define val_print neko_val_print 384 | #define val_gc neko_val_gc 385 | #define val_throw neko_val_throw 386 | #define val_rethrow neko_val_rethrow 387 | #define val_iter_fields neko_val_iter_fields 388 | #define val_field_name neko_val_field_name 389 | #define val_hash neko_val_hash 390 | #define k_hash neko_k_hash 391 | #define kind_share neko_kind_share 392 | #define kind_lookup neko_kind_lookup 393 | 394 | #define alloc_local neko_alloc_local 395 | #define local_get neko_local_get 396 | #define local_set neko_local_set 397 | #define free_local neko_free_local 398 | #define alloc_lock neko_alloc_lock 399 | #define lock_acquire neko_lock_acquire 400 | #define lock_try neko_lock_try 401 | #define lock_release neko_lock_release 402 | #define free_lock neko_free_lock 403 | 404 | C_FUNCTION_BEGIN 405 | 406 | VEXTERN vkind k_hash; 407 | 408 | VEXTERN value val_null; 409 | VEXTERN value val_true; 410 | VEXTERN value val_false; 411 | 412 | EXTERN value alloc_float( tfloat t ); 413 | EXTERN value alloc_int32( int i ); 414 | 415 | EXTERN value alloc_string( const char *str ); 416 | EXTERN value alloc_empty_string( unsigned int size ); 417 | EXTERN value copy_string( const char *str, int_val size ); 418 | 419 | EXTERN value val_this(); 420 | EXTERN field val_id( const char *str ); 421 | EXTERN value val_field( value o, field f ); 422 | EXTERN value alloc_object( value o ); 423 | EXTERN void alloc_field( value obj, field f, value v ); 424 | EXTERN void val_iter_fields( value obj, void f( value v, field f, void * ), void *p ); 425 | EXTERN value val_field_name( field f ); 426 | 427 | EXTERN value alloc_array( unsigned int n ); 428 | EXTERN value alloc_abstract( vkind k, void *data ); 429 | 430 | EXTERN value val_call0( value f ); 431 | EXTERN value val_call1( value f, value arg ); 432 | EXTERN value val_call2( value f, value arg1, value arg2 ); 433 | EXTERN value val_call3( value f, value arg1, value arg2, value arg3 ); 434 | EXTERN value val_callN( value f, value *args, int nargs ); 435 | EXTERN value val_ocall0( value o, field f ); 436 | EXTERN value val_ocall1( value o, field f, value arg ); 437 | EXTERN value val_ocall2( value o, field f, value arg1, value arg2 ); 438 | EXTERN value val_ocallN( value o, field f, value *args, int nargs ); 439 | EXTERN value val_callEx( value vthis, value f, value *args, int nargs, value *exc ); 440 | 441 | EXTERN value *alloc_root( unsigned int nvals ); 442 | EXTERN void free_root( value *r ); 443 | EXTERN char *alloc( unsigned int nbytes ); 444 | EXTERN char *alloc_private( unsigned int nbytes ); 445 | EXTERN value alloc_function( void *c_prim, unsigned int nargs, const char *name ); 446 | 447 | EXTERN buffer alloc_buffer( const char *init ); 448 | EXTERN void buffer_append( buffer b, const char *s ); 449 | EXTERN void buffer_append_sub( buffer b, const char *s, int_val len ); 450 | EXTERN void buffer_append_char( buffer b, char c ); 451 | EXTERN value buffer_to_string( buffer b ); 452 | EXTERN int buffer_length( buffer b ); 453 | EXTERN void val_buffer( buffer b, value v ); 454 | 455 | EXTERN int val_compare( value a, value b ); 456 | EXTERN void val_print( value s ); 457 | EXTERN void val_gc( value v, finalizer f ); 458 | EXTERN void val_throw( value v ); 459 | EXTERN void val_rethrow( value v ); 460 | EXTERN int val_hash( value v ); 461 | 462 | EXTERN void kind_share( vkind *k, const char *name ); 463 | EXTERN vkind kind_lookup( const char *name ); 464 | EXTERN void _neko_failure( value msg, const char *file, int line ); 465 | 466 | // MULTITHREADING API 467 | EXTERN mt_local *alloc_local(); 468 | EXTERN void *local_get( mt_local *l ); 469 | EXTERN void local_set( mt_local *l, void *v ); 470 | EXTERN void free_local( mt_local *l ); 471 | 472 | EXTERN mt_lock *alloc_lock(); 473 | EXTERN void lock_acquire( mt_lock *l ); 474 | EXTERN int lock_try( mt_lock *l ); 475 | EXTERN void lock_release( mt_lock *l ); 476 | EXTERN void free_lock( mt_lock *l ); 477 | 478 | C_FUNCTION_END 479 | 480 | #endif 481 | /* ************************************************************************ */ 482 | -------------------------------------------------------------------------------- /include/hl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C)2005-2016 Haxe Foundation 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | #ifndef HL_H 23 | #define HL_H 24 | 25 | /** 26 | Detailed documentation can be found here: 27 | https://github.com/HaxeFoundation/hashlink/wiki/ 28 | **/ 29 | 30 | #define HL_VERSION 0x010B00 31 | 32 | #if defined(_WIN32) 33 | # define HL_WIN 34 | # ifndef _DURANGO 35 | # define HL_WIN_DESKTOP 36 | # endif 37 | #endif 38 | 39 | #if defined(__APPLE__) || defined(__MACH__) || defined(macintosh) 40 | #include 41 | #if TARGET_OS_IOS 42 | #define HL_IOS 43 | #elif TARGET_OS_TV 44 | #define HL_TVOS 45 | #elif TARGET_OS_MAC 46 | #define HL_MAC 47 | #endif 48 | #endif 49 | 50 | #ifdef __ANDROID__ 51 | # define HL_ANDROID 52 | #endif 53 | 54 | #if defined(linux) || defined(__linux__) 55 | # define HL_LINUX 56 | # define _GNU_SOURCE 57 | #endif 58 | 59 | #if defined(HL_IOS) || defined(HL_ANDROID) || defined(HL_TVOS) 60 | # define HL_MOBILE 61 | #endif 62 | 63 | #ifdef __ORBIS__ 64 | # define HL_PS 65 | #endif 66 | 67 | #ifdef __NX__ 68 | # define HL_NX 69 | #endif 70 | 71 | #ifdef _DURANGO 72 | # define HL_XBO 73 | #endif 74 | 75 | #if defined(HL_PS) || defined(HL_NX) || defined(HL_XBO) 76 | # define HL_CONSOLE 77 | #endif 78 | 79 | #if (defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) && !defined(HL_CONSOLE) 80 | # define HL_BSD 81 | #endif 82 | 83 | #if defined(_64BITS) || defined(__x86_64__) || defined(_M_X64) || defined(__LP64__) 84 | # define HL_64 85 | #endif 86 | 87 | #if defined(__GNUC__) 88 | # define HL_GCC 89 | #endif 90 | 91 | #if defined(__MINGW32__) 92 | # define HL_MINGW 93 | #endif 94 | 95 | #if defined(__CYGWIN__) 96 | # define HL_CYGWIN 97 | #endif 98 | 99 | #if defined(__llvm__) 100 | # define HL_LLVM 101 | #endif 102 | 103 | #if defined(__clang__) 104 | # define HL_CLANG 105 | #endif 106 | 107 | #if defined(_MSC_VER) && !defined(HL_LLVM) 108 | # define HL_VCC 109 | # pragma warning(disable:4996) // remove deprecated C API usage warnings 110 | # pragma warning(disable:4055) // void* - to - function cast 111 | # pragma warning(disable:4152) // void* - to - function cast 112 | # pragma warning(disable:4201) // anonymous struct 113 | # pragma warning(disable:4127) // while( true ) 114 | # pragma warning(disable:4710) // inline disabled 115 | # pragma warning(disable:4711) // inline activated 116 | # pragma warning(disable:4255) // windows include 117 | # pragma warning(disable:4820) // windows include 118 | # pragma warning(disable:4668) // windows include 119 | # pragma warning(disable:4738) // return float bad performances 120 | #endif 121 | 122 | #if defined(HL_VCC) || defined(HL_MINGW) || defined(HL_CYGWIN) 123 | # define HL_WIN_CALL 124 | #endif 125 | 126 | #ifdef _DEBUG 127 | # define HL_DEBUG 128 | #endif 129 | 130 | #ifndef HL_CONSOLE 131 | # define HL_TRACK_ENABLE 132 | #endif 133 | 134 | #ifndef HL_NO_THREADS 135 | # define HL_THREADS 136 | # ifdef HL_VCC 137 | # define HL_THREAD_VAR __declspec( thread ) 138 | # define HL_THREAD_STATIC_VAR HL_THREAD_VAR static 139 | # else 140 | # define HL_THREAD_VAR __thread 141 | # define HL_THREAD_STATIC_VAR static HL_THREAD_VAR 142 | # endif 143 | #else 144 | # define HL_THREAD_VAR 145 | # define HL_THREAD_STATIC_VAR static 146 | #endif 147 | 148 | #include 149 | #ifndef HL_VCC 150 | # include 151 | #endif 152 | 153 | #if defined(HL_VCC) || defined(HL_MINGW) 154 | # define EXPORT __declspec( dllexport ) 155 | # define IMPORT __declspec( dllimport ) 156 | #else 157 | # define EXPORT 158 | # define IMPORT extern 159 | #endif 160 | 161 | #ifdef HL_64 162 | # define HL_WSIZE 8 163 | # define IS_64 1 164 | # ifdef HL_VCC 165 | # define _PTR_FMT L"%IX" 166 | # else 167 | # define _PTR_FMT u"%lX" 168 | # endif 169 | #else 170 | # define HL_WSIZE 4 171 | # define IS_64 0 172 | # ifdef HL_VCC 173 | # define _PTR_FMT L"%IX" 174 | # else 175 | # define _PTR_FMT u"%X" 176 | # endif 177 | #endif 178 | 179 | #ifdef __cplusplus 180 | # define C_FUNCTION_BEGIN extern "C" { 181 | # define C_FUNCTION_END }; 182 | #else 183 | # define C_FUNCTION_BEGIN 184 | # define C_FUNCTION_END 185 | # ifndef true 186 | # define true 1 187 | # define false 0 188 | typedef unsigned char bool; 189 | # endif 190 | #endif 191 | 192 | typedef intptr_t int_val; 193 | typedef long long int64; 194 | typedef unsigned long long uint64; 195 | 196 | #include 197 | #include 198 | #include 199 | 200 | #if defined(LIBHL_EXPORTS) 201 | #define HL_API extern EXPORT 202 | #elif defined(LIBHL_STATIC) 203 | #define HL_API extern 204 | #else 205 | #define HL_API IMPORT 206 | #endif 207 | 208 | // -------------- UNICODE ----------------------------------- 209 | 210 | #if defined(HL_WIN) && !defined(HL_LLVM) 211 | #if defined(HL_WIN_DESKTOP) && !defined(HL_MINGW) 212 | # include 213 | #elif defined(HL_WIN_DESKTOP) && defined(HL_MINGW) 214 | # include 215 | #else 216 | # include 217 | #endif 218 | # include 219 | typedef wchar_t uchar; 220 | # define USTR(str) L##str 221 | # define HL_NATIVE_UCHAR_FUN 222 | # define usprintf swprintf 223 | # define uprintf wprintf 224 | # define ustrlen wcslen 225 | # define ustrdup _wcsdup 226 | HL_API int uvszprintf( uchar *out, int out_size, const uchar *fmt, va_list arglist ); 227 | # define utod(s,end) wcstod(s,end) 228 | # define utoi(s,end) wcstol(s,end,10) 229 | # define ucmp(a,b) wcscmp(a,b) 230 | # define utostr(out,size,str) wcstombs(out,str,size) 231 | #elif defined(HL_MAC) 232 | typedef uint16_t uchar; 233 | # undef USTR 234 | # define USTR(str) u##str 235 | #else 236 | # include 237 | #if defined(HL_IOS) || defined(HL_TVOS) || defined(HL_MAC) 238 | #include 239 | #include 240 | typedef uint16_t char16_t; 241 | typedef uint32_t char32_t; 242 | #else 243 | # include 244 | #endif 245 | typedef char16_t uchar; 246 | # undef USTR 247 | # define USTR(str) u##str 248 | #endif 249 | 250 | #ifndef HL_NATIVE_UCHAR_FUN 251 | C_FUNCTION_BEGIN 252 | HL_API int ustrlen( const uchar *str ); 253 | HL_API uchar *ustrdup( const uchar *str ); 254 | HL_API double utod( const uchar *str, uchar **end ); 255 | HL_API int utoi( const uchar *str, uchar **end ); 256 | HL_API int ucmp( const uchar *a, const uchar *b ); 257 | HL_API int utostr( char *out, int out_size, const uchar *str ); 258 | HL_API int usprintf( uchar *out, int out_size, const uchar *fmt, ... ); 259 | HL_API int uvszprintf( uchar *out, int out_size, const uchar *fmt, va_list arglist ); 260 | HL_API void uprintf( const uchar *fmt, const uchar *str ); 261 | C_FUNCTION_END 262 | #endif 263 | 264 | #if defined(HL_VCC) 265 | # define hl_debug_break() if( IsDebuggerPresent() ) __debugbreak() 266 | #elif defined(HL_PS) && defined(_DEBUG) 267 | # define hl_debug_break() __debugbreak() 268 | #elif defined(HL_NX) 269 | C_FUNCTION_BEGIN 270 | HL_API void hl_debug_break( void ); 271 | C_FUNCTION_END 272 | #elif defined(HL_LINUX) && defined(__i386__) 273 | # ifdef HL_64 274 | # define hl_debug_break() \ 275 | if( hl_detect_debugger() ) \ 276 | __asm__("0: int3;" \ 277 | ".pushsection embed-breakpoints;" \ 278 | ".quad 0b;" \ 279 | ".popsection") 280 | # else 281 | # define hl_debug_break() \ 282 | if( hl_detect_debugger() ) \ 283 | __asm__("0: int3;" \ 284 | ".pushsection embed-breakpoints;" \ 285 | ".long 0b;" \ 286 | ".popsection") 287 | # endif 288 | #else 289 | # define hl_debug_break() 290 | #endif 291 | 292 | #ifdef HL_VCC 293 | # define HL_NO_RETURN(f) __declspec(noreturn) f 294 | # define HL_UNREACHABLE 295 | #else 296 | # define HL_NO_RETURN(f) f __attribute__((noreturn)) 297 | # define HL_UNREACHABLE __builtin_unreachable() 298 | #endif 299 | 300 | // ---- TYPES ------------------------------------------- 301 | 302 | typedef enum { 303 | HVOID = 0, 304 | HUI8 = 1, 305 | HUI16 = 2, 306 | HI32 = 3, 307 | HI64 = 4, 308 | HF32 = 5, 309 | HF64 = 6, 310 | HBOOL = 7, 311 | HBYTES = 8, 312 | HDYN = 9, 313 | HFUN = 10, 314 | HOBJ = 11, 315 | HARRAY = 12, 316 | HTYPE = 13, 317 | HREF = 14, 318 | HVIRTUAL= 15, 319 | HDYNOBJ = 16, 320 | HABSTRACT=17, 321 | HENUM = 18, 322 | HNULL = 19, 323 | HMETHOD = 20, 324 | HSTRUCT = 21, 325 | // --------- 326 | HLAST = 22, 327 | _H_FORCE_INT = 0x7FFFFFFF 328 | } hl_type_kind; 329 | 330 | typedef struct hl_type hl_type; 331 | typedef struct hl_runtime_obj hl_runtime_obj; 332 | typedef struct hl_alloc_block hl_alloc_block; 333 | typedef struct { hl_alloc_block *cur; } hl_alloc; 334 | typedef struct _hl_field_lookup hl_field_lookup; 335 | 336 | typedef struct { 337 | hl_alloc alloc; 338 | void **functions_ptrs; 339 | hl_type **functions_types; 340 | } hl_module_context; 341 | 342 | typedef struct { 343 | hl_type **args; 344 | hl_type *ret; 345 | int nargs; 346 | // storage for closure 347 | hl_type *parent; 348 | struct { 349 | hl_type_kind kind; 350 | void *p; 351 | } closure_type; 352 | struct { 353 | hl_type **args; 354 | hl_type *ret; 355 | int nargs; 356 | hl_type *parent; 357 | } closure; 358 | } hl_type_fun; 359 | 360 | typedef struct { 361 | const uchar *name; 362 | hl_type *t; 363 | int hashed_name; 364 | } hl_obj_field; 365 | 366 | typedef struct { 367 | const uchar *name; 368 | int findex; 369 | int pindex; 370 | int hashed_name; 371 | } hl_obj_proto; 372 | 373 | typedef struct { 374 | int nfields; 375 | int nproto; 376 | int nbindings; 377 | const uchar *name; 378 | hl_type *super; 379 | hl_obj_field *fields; 380 | hl_obj_proto *proto; 381 | int *bindings; 382 | void **global_value; 383 | hl_module_context *m; 384 | hl_runtime_obj *rt; 385 | } hl_type_obj; 386 | 387 | typedef struct { 388 | hl_obj_field *fields; 389 | int nfields; 390 | // runtime 391 | int dataSize; 392 | int *indexes; 393 | hl_field_lookup *lookup; 394 | } hl_type_virtual; 395 | 396 | typedef struct { 397 | const uchar *name; 398 | int nparams; 399 | hl_type **params; 400 | int size; 401 | bool hasptr; 402 | int *offsets; 403 | } hl_enum_construct; 404 | 405 | typedef struct { 406 | const uchar *name; 407 | int nconstructs; 408 | hl_enum_construct *constructs; 409 | void **global_value; 410 | } hl_type_enum; 411 | 412 | struct hl_type { 413 | hl_type_kind kind; 414 | union { 415 | const uchar *abs_name; 416 | hl_type_fun *fun; 417 | hl_type_obj *obj; 418 | hl_type_enum *tenum; 419 | hl_type_virtual *virt; 420 | hl_type *tparam; 421 | }; 422 | void **vobj_proto; 423 | unsigned int *mark_bits; 424 | }; 425 | 426 | C_FUNCTION_BEGIN 427 | 428 | HL_API int hl_type_size( hl_type *t ); 429 | #define hl_pad_size(size,t) ((t)->kind == HVOID ? 0 : ((-(size)) & (hl_type_size(t) - 1))) 430 | HL_API int hl_pad_struct( int size, hl_type *t ); 431 | 432 | HL_API hl_runtime_obj *hl_get_obj_rt( hl_type *ot ); 433 | HL_API hl_runtime_obj *hl_get_obj_proto( hl_type *ot ); 434 | HL_API void hl_flush_proto( hl_type *ot ); 435 | HL_API void hl_init_enum( hl_type *et, hl_module_context *m ); 436 | 437 | /* -------------------- VALUES ------------------------------ */ 438 | 439 | typedef unsigned char vbyte; 440 | 441 | typedef struct { 442 | hl_type *t; 443 | # ifndef HL_64 444 | int __pad; // force align on 16 bytes for double 445 | # endif 446 | union { 447 | bool b; 448 | unsigned char ui8; 449 | unsigned short ui16; 450 | int i; 451 | float f; 452 | double d; 453 | vbyte *bytes; 454 | void *ptr; 455 | int64 i64; 456 | } v; 457 | } vdynamic; 458 | 459 | typedef struct { 460 | hl_type *t; 461 | /* fields data */ 462 | } vobj; 463 | 464 | typedef struct _vvirtual vvirtual; 465 | struct _vvirtual { 466 | hl_type *t; 467 | vdynamic *value; 468 | vvirtual *next; 469 | }; 470 | 471 | #define hl_vfields(v) ((void**)(((vvirtual*)(v))+1)) 472 | 473 | typedef struct { 474 | hl_type *t; 475 | hl_type *at; 476 | int size; 477 | int __pad; // force align on 16 bytes for double 478 | } varray; 479 | 480 | typedef struct _vclosure { 481 | hl_type *t; 482 | void *fun; 483 | int hasValue; 484 | # ifdef HL_64 485 | int __pad; 486 | # endif 487 | void *value; 488 | } vclosure; 489 | 490 | typedef struct { 491 | vclosure cl; 492 | vclosure *wrappedFun; 493 | } vclosure_wrapper; 494 | 495 | struct _hl_field_lookup { 496 | hl_type *t; 497 | int hashed_name; 498 | int field_index; // negative or zero : index in methods 499 | }; 500 | 501 | typedef struct { 502 | void *ptr; 503 | hl_type *closure; 504 | int fid; 505 | } hl_runtime_binding; 506 | 507 | struct hl_runtime_obj { 508 | hl_type *t; 509 | // absolute 510 | int nfields; 511 | int nproto; 512 | int size; 513 | int nmethods; 514 | int nbindings; 515 | bool hasPtr; 516 | void **methods; 517 | int *fields_indexes; 518 | hl_runtime_binding *bindings; 519 | hl_runtime_obj *parent; 520 | const uchar *(*toStringFun)( vdynamic *obj ); 521 | int (*compareFun)( vdynamic *a, vdynamic *b ); 522 | vdynamic *(*castFun)( vdynamic *obj, hl_type *t ); 523 | vdynamic *(*getFieldFun)( vdynamic *obj, int hfield ); 524 | // relative 525 | int nlookup; 526 | hl_field_lookup *lookup; 527 | }; 528 | 529 | typedef struct { 530 | hl_type *t; 531 | hl_field_lookup *lookup; 532 | char *raw_data; 533 | void **values; 534 | int nfields; 535 | int raw_size; 536 | int nvalues; 537 | vvirtual *virtuals; 538 | } vdynobj; 539 | 540 | typedef struct _venum { 541 | hl_type *t; 542 | int index; 543 | } venum; 544 | 545 | HL_API hl_type hlt_void; 546 | HL_API hl_type hlt_i32; 547 | HL_API hl_type hlt_i64; 548 | HL_API hl_type hlt_f64; 549 | HL_API hl_type hlt_f32; 550 | HL_API hl_type hlt_dyn; 551 | HL_API hl_type hlt_array; 552 | HL_API hl_type hlt_bytes; 553 | HL_API hl_type hlt_dynobj; 554 | HL_API hl_type hlt_bool; 555 | HL_API hl_type hlt_abstract; 556 | 557 | HL_API double hl_nan( void ); 558 | HL_API bool hl_is_dynamic( hl_type *t ); 559 | #define hl_is_ptr(t) ((t)->kind >= HBYTES) 560 | HL_API bool hl_same_type( hl_type *a, hl_type *b ); 561 | HL_API bool hl_safe_cast( hl_type *t, hl_type *to ); 562 | 563 | #define hl_aptr(a,t) ((t*)(((varray*)(a))+1)) 564 | 565 | HL_API varray *hl_alloc_array( hl_type *t, int size ); 566 | HL_API vdynamic *hl_alloc_dynamic( hl_type *t ); 567 | HL_API vdynamic *hl_alloc_dynbool( bool b ); 568 | HL_API vdynamic *hl_alloc_obj( hl_type *t ); 569 | HL_API venum *hl_alloc_enum( hl_type *t, int index ); 570 | HL_API vvirtual *hl_alloc_virtual( hl_type *t ); 571 | HL_API vdynobj *hl_alloc_dynobj( void ); 572 | HL_API vbyte *hl_alloc_bytes( int size ); 573 | HL_API vbyte *hl_copy_bytes( const vbyte *byte, int size ); 574 | HL_API int hl_utf8_length( const vbyte *s, int pos ); 575 | HL_API int hl_from_utf8( uchar *out, int outLen, const char *str ); 576 | HL_API char *hl_to_utf8( const uchar *bytes ); 577 | HL_API uchar *hl_to_utf16( const char *str ); 578 | HL_API vdynamic *hl_virtual_make_value( vvirtual *v ); 579 | HL_API hl_obj_field *hl_obj_field_fetch( hl_type *t, int fid ); 580 | 581 | HL_API int hl_hash( vbyte *name ); 582 | HL_API int hl_hash_utf8( const char *str ); // no cache 583 | HL_API int hl_hash_gen( const uchar *name, bool cache_name ); 584 | HL_API vbyte *hl_field_name( int hash ); 585 | 586 | #define hl_error(msg, ...) hl_throw(hl_alloc_strbytes(USTR(msg), ## __VA_ARGS__)) 587 | 588 | HL_API vdynamic *hl_alloc_strbytes( const uchar *msg, ... ); 589 | HL_API void hl_assert( void ); 590 | HL_API HL_NO_RETURN( void hl_throw( vdynamic *v ) ); 591 | HL_API HL_NO_RETURN( void hl_rethrow( vdynamic *v ) ); 592 | HL_API HL_NO_RETURN( void hl_null_access( void ) ); 593 | HL_API void hl_setup_longjump( void *j ); 594 | HL_API void hl_setup_exception( void *resolve_symbol, void *capture_stack ); 595 | HL_API void hl_dump_stack( void ); 596 | HL_API varray *hl_exception_stack( void ); 597 | HL_API bool hl_detect_debugger( void ); 598 | 599 | HL_API vvirtual *hl_to_virtual( hl_type *vt, vdynamic *obj ); 600 | HL_API void hl_init_virtual( hl_type *vt, hl_module_context *ctx ); 601 | HL_API hl_field_lookup *hl_lookup_find( hl_field_lookup *l, int size, int hash ); 602 | HL_API hl_field_lookup *hl_lookup_insert( hl_field_lookup *l, int size, int hash, hl_type *t, int index ); 603 | 604 | HL_API int hl_dyn_geti( vdynamic *d, int hfield, hl_type *t ); 605 | HL_API void *hl_dyn_getp( vdynamic *d, int hfield, hl_type *t ); 606 | HL_API float hl_dyn_getf( vdynamic *d, int hfield ); 607 | HL_API double hl_dyn_getd( vdynamic *d, int hfield ); 608 | 609 | HL_API int hl_dyn_casti( void *data, hl_type *t, hl_type *to ); 610 | HL_API void *hl_dyn_castp( void *data, hl_type *t, hl_type *to ); 611 | HL_API float hl_dyn_castf( void *data, hl_type *t ); 612 | HL_API double hl_dyn_castd( void *data, hl_type *t ); 613 | 614 | #define hl_invalid_comparison 0xAABBCCDD 615 | HL_API int hl_dyn_compare( vdynamic *a, vdynamic *b ); 616 | HL_API vdynamic *hl_make_dyn( void *data, hl_type *t ); 617 | HL_API void hl_write_dyn( void *data, hl_type *t, vdynamic *v, bool is_tmp ); 618 | 619 | HL_API void hl_dyn_seti( vdynamic *d, int hfield, hl_type *t, int value ); 620 | HL_API void hl_dyn_setp( vdynamic *d, int hfield, hl_type *t, void *ptr ); 621 | HL_API void hl_dyn_setf( vdynamic *d, int hfield, float f ); 622 | HL_API void hl_dyn_setd( vdynamic *d, int hfield, double v ); 623 | 624 | typedef enum { 625 | OpAdd, 626 | OpSub, 627 | OpMul, 628 | OpMod, 629 | OpDiv, 630 | OpShl, 631 | OpShr, 632 | OpUShr, 633 | OpAnd, 634 | OpOr, 635 | OpXor, 636 | OpLast 637 | } DynOp; 638 | HL_API vdynamic *hl_dyn_op( int op, vdynamic *a, vdynamic *b ); 639 | 640 | HL_API vclosure *hl_alloc_closure_void( hl_type *t, void *fvalue ); 641 | HL_API vclosure *hl_alloc_closure_ptr( hl_type *fullt, void *fvalue, void *ptr ); 642 | HL_API vclosure *hl_make_fun_wrapper( vclosure *c, hl_type *to ); 643 | HL_API void *hl_wrapper_call( void *value, void **args, vdynamic *ret ); 644 | HL_API void *hl_dyn_call_obj( vdynamic *obj, hl_type *ft, int hfield, void **args, vdynamic *ret ); 645 | HL_API vdynamic *hl_dyn_call( vclosure *c, vdynamic **args, int nargs ); 646 | HL_API vdynamic *hl_dyn_call_safe( vclosure *c, vdynamic **args, int nargs, bool *isException ); 647 | 648 | /* 649 | These macros should be only used when the closure `cl` has been type checked beforehand 650 | so you are sure it's of the used typed. Otherwise use hl_dyn_call 651 | */ 652 | #define hl_call0(ret,cl) \ 653 | (cl->hasValue ? ((ret(*)(vdynamic*))cl->fun)(cl->value) : ((ret(*)())cl->fun)()) 654 | #define hl_call1(ret,cl,t,v) \ 655 | (cl->hasValue ? ((ret(*)(vdynamic*,t))cl->fun)(cl->value,v) : ((ret(*)(t))cl->fun)(v)) 656 | #define hl_call2(ret,cl,t1,v1,t2,v2) \ 657 | (cl->hasValue ? ((ret(*)(vdynamic*,t1,t2))cl->fun)(cl->value,v1,v2) : ((ret(*)(t1,t2))cl->fun)(v1,v2)) 658 | #define hl_call3(ret,cl,t1,v1,t2,v2,t3,v3) \ 659 | (cl->hasValue ? ((ret(*)(vdynamic*,t1,t2,t3))cl->fun)(cl->value,v1,v2,v3) : ((ret(*)(t1,t2,t3))cl->fun)(v1,v2,v3)) 660 | #define hl_call4(ret,cl,t1,v1,t2,v2,t3,v3,t4,v4) \ 661 | (cl->hasValue ? ((ret(*)(vdynamic*,t1,t2,t3,t4))cl->fun)(cl->value,v1,v2,v3,v4) : ((ret(*)(t1,t2,t3,t4))cl->fun)(v1,v2,v3,v4)) 662 | 663 | // ----------------------- THREADS -------------------------------------------------- 664 | 665 | struct _hl_thread; 666 | struct _hl_mutex; 667 | struct _hl_tls; 668 | typedef struct _hl_thread hl_thread; 669 | typedef struct _hl_mutex hl_mutex; 670 | typedef struct _hl_tls hl_tls; 671 | 672 | HL_API hl_thread *hl_thread_start( void *callback, void *param, bool withGC ); 673 | HL_API hl_thread *hl_thread_current( void ); 674 | HL_API void hl_thread_yield(void); 675 | HL_API void hl_register_thread( void *stack_top ); 676 | HL_API void hl_unregister_thread( void ); 677 | 678 | HL_API hl_mutex *hl_mutex_alloc( bool gc_thread ); 679 | HL_API void hl_mutex_acquire( hl_mutex *l ); 680 | HL_API bool hl_mutex_try_acquire( hl_mutex *l ); 681 | HL_API void hl_mutex_release( hl_mutex *l ); 682 | HL_API void hl_mutex_free( hl_mutex *l ); 683 | 684 | HL_API hl_tls *hl_tls_alloc( bool gc_value ); 685 | HL_API void hl_tls_set( hl_tls *l, void *value ); 686 | HL_API void *hl_tls_get( hl_tls *l ); 687 | HL_API void hl_tls_free( hl_tls *l ); 688 | 689 | // ----------------------- ALLOC -------------------------------------------------- 690 | 691 | #define MEM_HAS_PTR(kind) (!((kind)&2)) 692 | #define MEM_KIND_DYNAMIC 0 693 | #define MEM_KIND_RAW 1 694 | #define MEM_KIND_NOPTR 2 695 | #define MEM_KIND_FINALIZER 3 696 | #define MEM_ALIGN_DOUBLE 128 697 | #define MEM_ZERO 256 698 | 699 | HL_API void *hl_gc_alloc_gen( hl_type *t, int size, int flags ); 700 | HL_API void hl_add_root( void *ptr ); 701 | HL_API void hl_remove_root( void *ptr ); 702 | HL_API void hl_gc_major( void ); 703 | HL_API bool hl_is_gc_ptr( void *ptr ); 704 | 705 | HL_API void hl_blocking( bool b ); 706 | HL_API bool hl_is_blocking( void ); 707 | 708 | typedef void (*hl_types_dump)( void (*)( void *, int) ); 709 | HL_API void hl_gc_set_dump_types( hl_types_dump tdump ); 710 | 711 | #define hl_gc_alloc_noptr(size) hl_gc_alloc_gen(&hlt_bytes,size,MEM_KIND_NOPTR) 712 | #define hl_gc_alloc(t,size) hl_gc_alloc_gen(t,size,MEM_KIND_DYNAMIC) 713 | #define hl_gc_alloc_raw(size) hl_gc_alloc_gen(&hlt_abstract,size,MEM_KIND_RAW) 714 | #define hl_gc_alloc_finalizer(size) hl_gc_alloc_gen(&hlt_abstract,size,MEM_KIND_FINALIZER) 715 | 716 | HL_API void hl_alloc_init( hl_alloc *a ); 717 | HL_API void *hl_malloc( hl_alloc *a, int size ); 718 | HL_API void *hl_zalloc( hl_alloc *a, int size ); 719 | HL_API void hl_free( hl_alloc *a ); 720 | 721 | HL_API void hl_global_init( void ); 722 | HL_API void hl_global_free( void ); 723 | 724 | HL_API void *hl_alloc_executable_memory( int size ); 725 | HL_API void hl_free_executable_memory( void *ptr, int size ); 726 | 727 | // ----------------------- BUFFER -------------------------------------------------- 728 | 729 | typedef struct hl_buffer hl_buffer; 730 | 731 | HL_API hl_buffer *hl_alloc_buffer( void ); 732 | HL_API void hl_buffer_val( hl_buffer *b, vdynamic *v ); 733 | HL_API void hl_buffer_char( hl_buffer *b, uchar c ); 734 | HL_API void hl_buffer_str( hl_buffer *b, const uchar *str ); 735 | HL_API void hl_buffer_cstr( hl_buffer *b, const char *str ); 736 | HL_API void hl_buffer_str_sub( hl_buffer *b, const uchar *str, int len ); 737 | HL_API int hl_buffer_length( hl_buffer *b ); 738 | HL_API uchar *hl_buffer_content( hl_buffer *b, int *len ); 739 | HL_API uchar *hl_to_string( vdynamic *v ); 740 | HL_API const uchar *hl_type_str( hl_type *t ); 741 | HL_API void hl_throw_buffer( hl_buffer *b ); 742 | 743 | // ----------------------- FFI ------------------------------------------------------ 744 | 745 | // match GNU C++ mangling 746 | #define TYPE_STR "vcsilfdbBDPOATR??X?N" 747 | 748 | #undef _VOID 749 | #define _NO_ARG 750 | #define _VOID "v" 751 | #define _I8 "c" 752 | #define _I16 "s" 753 | #define _I32 "i" 754 | #define _I64 "l" 755 | #define _F32 "f" 756 | #define _F64 "d" 757 | #define _BOOL "b" 758 | #define _BYTES "B" 759 | #define _DYN "D" 760 | #define _FUN(t, args) "P" args "_" t 761 | #define _OBJ(fields) "O" fields "_" 762 | #define _ARR "A" 763 | #define _TYPE "T" 764 | #define _REF(t) "R" t 765 | #define _ABSTRACT(name) "X" #name "_" 766 | #undef _NULL 767 | #define _NULL(t) "N" t 768 | 769 | #undef _STRING 770 | #define _STRING _OBJ(_BYTES _I32) 771 | 772 | typedef struct { 773 | hl_type *t; 774 | uchar *bytes; 775 | int length; 776 | } vstring; 777 | 778 | #define DEFINE_PRIM(t,name,args) DEFINE_PRIM_WITH_NAME(t,name,args,name) 779 | #define _DEFINE_PRIM_WITH_NAME(t,name,args,realName) C_FUNCTION_BEGIN EXPORT void *hlp_##realName( const char **sign ) { *sign = _FUN(t,args); return (void*)(&HL_NAME(name)); } C_FUNCTION_END 780 | 781 | #if !defined(HL_NAME) 782 | # define HL_NAME(p) p 783 | # ifdef LIBHL_EXPORTS 784 | # define HL_PRIM EXPORT 785 | # undef DEFINE_PRIM 786 | # define DEFINE_PRIM(t,name,args) _DEFINE_PRIM_WITH_NAME(t,hl_##name,args,name) 787 | # define DEFINE_PRIM_WITH_NAME _DEFINE_PRIM_WITH_NAME 788 | # else 789 | # define HL_PRIM 790 | # define DEFINE_PRIM_WITH_NAME(t,name,args,realName) 791 | # endif 792 | #elif defined(LIBHL_STATIC) 793 | # ifdef __cplusplus 794 | # define HL_PRIM extern "C" 795 | # else 796 | # define HL_PRIM 797 | # endif 798 | #define DEFINE_PRIM_WITH_NAME(t,name,args,realName) 799 | #else 800 | # ifdef __cplusplus 801 | # define HL_PRIM extern "C" EXPORT 802 | # else 803 | # define HL_PRIM EXPORT 804 | # endif 805 | # define DEFINE_PRIM_WITH_NAME _DEFINE_PRIM_WITH_NAME 806 | #endif 807 | 808 | #if defined(HL_GCC) && !defined(HL_CONSOLE) 809 | # ifdef HL_CLANG 810 | # define HL_NO_OPT __attribute__ ((optnone)) 811 | # else 812 | # define HL_NO_OPT __attribute__((optimize("-O0"))) 813 | # endif 814 | #else 815 | # define HL_NO_OPT 816 | #endif 817 | 818 | // -------------- EXTRA ------------------------------------ 819 | 820 | #define hl_fatal(msg) hl_fatal_error(msg,__FILE__,__LINE__) 821 | #define hl_fatal1(msg,p0) hl_fatal_fmt(__FILE__,__LINE__,msg,p0) 822 | #define hl_fatal2(msg,p0,p1) hl_fatal_fmt(__FILE__,__LINE__,msg,p0,p1) 823 | #define hl_fatal3(msg,p0,p1,p2) hl_fatal_fmt(__FILE__,__LINE__,msg,p0,p1,p2) 824 | #define hl_fatal4(msg,p0,p1,p2,p3) hl_fatal_fmt(__FILE__,__LINE__,msg,p0,p1,p2,p3) 825 | HL_API void *hl_fatal_error( const char *msg, const char *file, int line ); 826 | HL_API void hl_fatal_fmt( const char *file, int line, const char *fmt, ...); 827 | HL_API void hl_sys_init(void **args, int nargs, void *hlfile); 828 | HL_API void hl_setup_callbacks(void *sc, void *gw); 829 | HL_API void hl_setup_reload_check( void *freload, void *param ); 830 | 831 | #include 832 | typedef struct _hl_trap_ctx hl_trap_ctx; 833 | struct _hl_trap_ctx { 834 | jmp_buf buf; 835 | hl_trap_ctx *prev; 836 | vdynamic *tcheck; 837 | }; 838 | #define hl_trap(ctx,r,label) { hl_thread_info *__tinf = hl_get_thread(); ctx.tcheck = NULL; ctx.prev = __tinf->trap_current; __tinf->trap_current = &ctx; if( setjmp(ctx.buf) ) { r = __tinf->exc_value; goto label; } } 839 | #define hl_endtrap(ctx) hl_get_thread()->trap_current = ctx.prev 840 | 841 | #define HL_EXC_MAX_STACK 0x100 842 | #define HL_EXC_RETHROW 1 843 | #define HL_EXC_CATCH_ALL 2 844 | #define HL_EXC_IS_THROW 4 845 | #define HL_THREAD_INVISIBLE 16 846 | #define HL_THREAD_PROFILER_PAUSED 32 847 | #define HL_TREAD_TRACK_SHIFT 16 848 | 849 | #define HL_TRACK_ALLOC 1 850 | #define HL_TRACK_CAST 2 851 | #define HL_TRACK_DYNFIELD 4 852 | #define HL_TRACK_DYNCALL 8 853 | #define HL_TRACK_MASK (HL_TRACK_ALLOC | HL_TRACK_CAST | HL_TRACK_DYNFIELD | HL_TRACK_DYNCALL) 854 | 855 | typedef struct { 856 | int thread_id; 857 | // gc vars 858 | volatile int gc_blocking; 859 | void *stack_top; 860 | void *stack_cur; 861 | // exception handling 862 | hl_trap_ctx *trap_current; 863 | hl_trap_ctx *trap_uncaught; 864 | vclosure *exc_handler; 865 | vdynamic *exc_value; 866 | int flags; 867 | int exc_stack_count; 868 | // extra 869 | jmp_buf gc_regs; 870 | void *exc_stack_trace[HL_EXC_MAX_STACK]; 871 | } hl_thread_info; 872 | 873 | HL_API hl_thread_info *hl_get_thread(); 874 | 875 | #ifdef HL_TRACK_ENABLE 876 | 877 | typedef struct { 878 | int flags; 879 | void (*on_alloc)(hl_type *,int,int,void*); 880 | void (*on_cast)(hl_type *, hl_type*); 881 | void (*on_dynfield)( vdynamic *, int ); 882 | void (*on_dyncall)( vdynamic *, int ); 883 | } hl_track_info; 884 | 885 | #define hl_is_tracking(flag) ((hl_track.flags&(flag)) && (hl_get_thread()->flags & (flag<