mirror of https://github.com/mono/CppSharp.git
21 changed files with 719 additions and 33 deletions
@ -0,0 +1,73 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.Cpp; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Emscripten |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Emscripten generator responsible for driving the generation of binding files.
|
||||||
|
/// Embind documentation: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html
|
||||||
|
/// </summary>
|
||||||
|
public class EmscriptenGenerator : CppGenerator |
||||||
|
{ |
||||||
|
public EmscriptenGenerator(BindingContext context) : base(context) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override List<GeneratorOutput> Generate() |
||||||
|
{ |
||||||
|
var outputs = base.Generate(); |
||||||
|
|
||||||
|
foreach (var module in Context.Options.Modules) |
||||||
|
{ |
||||||
|
if (module == Context.Options.SystemModule) |
||||||
|
continue; |
||||||
|
|
||||||
|
var output = GenerateModule(module); |
||||||
|
if (output != null) |
||||||
|
{ |
||||||
|
OnUnitGenerated(output); |
||||||
|
outputs.Add(output); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return outputs; |
||||||
|
} |
||||||
|
|
||||||
|
public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units) |
||||||
|
{ |
||||||
|
var outputs = new List<CodeGenerator>(); |
||||||
|
|
||||||
|
var header = new EmscriptenHeaders(Context, units); |
||||||
|
outputs.Add(header); |
||||||
|
|
||||||
|
var source = new EmscriptenSources(Context, units); |
||||||
|
outputs.Add(source); |
||||||
|
|
||||||
|
return outputs; |
||||||
|
} |
||||||
|
|
||||||
|
public override GeneratorOutput GenerateModule(Module module) |
||||||
|
{ |
||||||
|
if (module == Context.Options.SystemModule) |
||||||
|
return null; |
||||||
|
|
||||||
|
var moduleGen = new EmscriptenModule(Context, module); |
||||||
|
|
||||||
|
var output = new GeneratorOutput |
||||||
|
{ |
||||||
|
TranslationUnit = new TranslationUnit |
||||||
|
{ |
||||||
|
FilePath = $"{module.LibraryName}_embind_module.cpp", |
||||||
|
Module = module |
||||||
|
}, |
||||||
|
Outputs = new List<CodeGenerator> { moduleGen } |
||||||
|
}; |
||||||
|
|
||||||
|
output.Outputs[0].Process(); |
||||||
|
|
||||||
|
return output; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using CppSharp.AST; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Emscripten |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Generates Emscripten Embind C/C++ header files.
|
||||||
|
/// Embind documentation: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html
|
||||||
|
/// </summary>
|
||||||
|
public class EmscriptenHeaders : EmscriptenCodeGenerator |
||||||
|
{ |
||||||
|
public EmscriptenHeaders(BindingContext context, IEnumerable<TranslationUnit> units) |
||||||
|
: base(context, units) |
||||||
|
{ |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
} |
||||||
|
|
||||||
|
//public override bool ShouldGenerateNamespaces => false;
|
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
GenerateFilePreamble(CommentKind.BCPL); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Includes); |
||||||
|
WriteLine("#pragma once"); |
||||||
|
NewLine(); |
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
var name = GetTranslationUnitName(TranslationUnit); |
||||||
|
WriteLine($"extern \"C\" void embind_init_{name}();"); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEvent(Event @event) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFieldDecl(Field field) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
using CppSharp.Generators.C; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Emscripten |
||||||
|
{ |
||||||
|
public class EmscriptenMarshalNativeToManagedPrinter : MarshalPrinter<MarshalContext, CppTypePrinter> |
||||||
|
{ |
||||||
|
public EmscriptenMarshalNativeToManagedPrinter(MarshalContext marshalContext) |
||||||
|
: base(marshalContext) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class EmscriptenMarshalManagedToNativePrinter : MarshalPrinter<MarshalContext, CppTypePrinter> |
||||||
|
{ |
||||||
|
public EmscriptenMarshalManagedToNativePrinter(MarshalContext ctx) |
||||||
|
: base(ctx) |
||||||
|
{ |
||||||
|
Context.MarshalToNative = this; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Emscripten |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Generates Emscripten module init files.
|
||||||
|
/// Embind documentation: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html
|
||||||
|
/// </summary>
|
||||||
|
public class EmscriptenModule : EmscriptenCodeGenerator |
||||||
|
{ |
||||||
|
private readonly Module module; |
||||||
|
|
||||||
|
public EmscriptenModule(BindingContext context, Module module) |
||||||
|
: base(context, module.Units.GetGenerated()) |
||||||
|
{ |
||||||
|
this.module = module; |
||||||
|
} |
||||||
|
|
||||||
|
public override string FileExtension { get; } = "cpp"; |
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
GenerateFilePreamble(CommentKind.BCPL); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Includes); |
||||||
|
{ |
||||||
|
WriteInclude(new CInclude() |
||||||
|
{ |
||||||
|
File = "emscripten/bind.h", |
||||||
|
Kind = CInclude.IncludeKind.Angled |
||||||
|
}); |
||||||
|
|
||||||
|
foreach (var unit in TranslationUnits) |
||||||
|
WriteInclude(GetIncludeFileName(Context, unit), CInclude.IncludeKind.Quoted); |
||||||
|
} |
||||||
|
PopBlock(NewLineKind.Always); |
||||||
|
|
||||||
|
WriteLine("extern \"C\" {"); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
PushBlock(BlockKind.ForwardReferences); |
||||||
|
{ |
||||||
|
foreach (var unit in TranslationUnits.Where(unit => unit.IsGenerated)) |
||||||
|
{ |
||||||
|
var name = GetTranslationUnitName(unit); |
||||||
|
WriteLine($"void embind_init_{name}();"); |
||||||
|
} |
||||||
|
} |
||||||
|
PopBlock(NewLineKind.Always); |
||||||
|
|
||||||
|
var moduleName = module.LibraryName; |
||||||
|
WriteLine($"void embind_init_{moduleName}()"); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
foreach (var unit in TranslationUnits) |
||||||
|
{ |
||||||
|
var name = GetTranslationUnitName(unit); |
||||||
|
WriteLine($"embind_init_{name}();"); |
||||||
|
} |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
|
||||||
|
NewLine(); |
||||||
|
WriteLine("}"); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
WriteLine($"static struct EmBindInit_{moduleName} : emscripten::internal::InitFunc {{"); |
||||||
|
WriteLineIndent($"EmBindInit_{moduleName}() : InitFunc(embind_init_{moduleName}) {{}}"); |
||||||
|
WriteLine($"}} EmBindInit_{moduleName}_instance;"); |
||||||
|
} |
||||||
|
|
||||||
|
public static string GetIncludeFileName(BindingContext context, TranslationUnit unit) |
||||||
|
{ |
||||||
|
// TODO: Replace with GetIncludePath
|
||||||
|
string file; |
||||||
|
if (context.Options.GenerateName != null) |
||||||
|
file = context.Options.GenerateName(unit); |
||||||
|
else |
||||||
|
file = Path.GetFileNameWithoutExtension(unit.FileName) |
||||||
|
.Replace('\\', '/'); |
||||||
|
|
||||||
|
return $"{file}.h"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,202 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.AST.Extensions; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
using CppSharp.Generators.Cpp; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Emscripten |
||||||
|
{ |
||||||
|
public class EmscriptenCodeGenerator : MethodGroupCodeGenerator |
||||||
|
{ |
||||||
|
protected EmscriptenCodeGenerator(BindingContext context, IEnumerable<TranslationUnit> units) |
||||||
|
: base(context, units) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public virtual MarshalPrinter<MarshalContext, CppTypePrinter> GetMarshalManagedToNativePrinter(MarshalContext ctx) |
||||||
|
{ |
||||||
|
return new EmscriptenMarshalManagedToNativePrinter(ctx); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual MarshalPrinter<MarshalContext, CppTypePrinter> GetMarshalNativeToManagedPrinter(MarshalContext ctx) |
||||||
|
{ |
||||||
|
return new EmscriptenMarshalNativeToManagedPrinter(ctx); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassTemplateDecl(ClassTemplate template) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionTemplateDecl(FunctionTemplate template) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates Emscripten C/C++ source files.
|
||||||
|
/// Embind documentation: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html
|
||||||
|
/// </summary>
|
||||||
|
public class EmscriptenSources : EmscriptenCodeGenerator |
||||||
|
{ |
||||||
|
public override string FileExtension => "cpp"; |
||||||
|
|
||||||
|
public EmscriptenSources(BindingContext context, IEnumerable<TranslationUnit> units) |
||||||
|
: base(context, units) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
GenerateFilePreamble(CommentKind.BCPL); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Includes); |
||||||
|
{ |
||||||
|
WriteInclude(new CInclude() |
||||||
|
{ |
||||||
|
File = "emscripten/bind.h", |
||||||
|
Kind = CInclude.IncludeKind.Angled |
||||||
|
}); |
||||||
|
|
||||||
|
foreach (var unit in TranslationUnits) |
||||||
|
{ |
||||||
|
WriteInclude(unit.IncludePath, CInclude.IncludeKind.Angled); |
||||||
|
} |
||||||
|
} |
||||||
|
PopBlock(NewLineKind.Always); |
||||||
|
|
||||||
|
var name = GetTranslationUnitName(TranslationUnit); |
||||||
|
WriteLine($"extern \"C\" void embind_init_{name}()"); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
VisitNamespace(TranslationUnit); |
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (@class.IsIncomplete) |
||||||
|
return true; |
||||||
|
|
||||||
|
PushBlock(); |
||||||
|
Write($"emscripten::class_<{@class.QualifiedOriginalName}"); |
||||||
|
if (@class.HasBaseClass) |
||||||
|
Write($", emscripten::base<{@class.BaseClass.QualifiedOriginalName}>"); |
||||||
|
WriteLine($">(\"{@class.Name}\")"); |
||||||
|
|
||||||
|
VisitClassDeclContext(@class); |
||||||
|
|
||||||
|
WriteLineIndent(";"); |
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitClassConstructors(IEnumerable<Method> ctors) |
||||||
|
{ |
||||||
|
var overloadCheck = new HashSet<int>(); |
||||||
|
foreach (var ctor in ctors) |
||||||
|
{ |
||||||
|
if (overloadCheck.Contains(ctor.Parameters.Count)) |
||||||
|
{ |
||||||
|
Console.WriteLine($"Ignoring overloaded ctor: {ctor.QualifiedOriginalName}"); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
var cppTypePrinter = new CppTypePrinter(Context) |
||||||
|
{ |
||||||
|
PrintFlavorKind = CppTypePrintFlavorKind.Cpp |
||||||
|
}; |
||||||
|
cppTypePrinter.PushContext(TypePrinterContextKind.Native); |
||||||
|
|
||||||
|
var parameters = ctor.Parameters.Select(p => p.Type.Visit(cppTypePrinter).Type); |
||||||
|
WriteLineIndent($".constructor<{string.Join(", ", parameters)}>()"); |
||||||
|
|
||||||
|
overloadCheck.Add(ctor.Parameters.Count); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMethodDecl(Method method) |
||||||
|
{ |
||||||
|
Indent(); |
||||||
|
var ret = VisitFunctionDecl(method); |
||||||
|
Unindent(); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFieldDecl(Field field) |
||||||
|
{ |
||||||
|
WriteLineIndent($".field(\"{field.Name}\", &{field.Class.QualifiedOriginalName}::{field.OriginalName})"); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override void GenerateMethodGroup(List<Method> @group) |
||||||
|
{ |
||||||
|
if (@group.Count > 1) |
||||||
|
{ |
||||||
|
Console.WriteLine($"Ignoring method group: {@group.First().QualifiedOriginalName}"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
base.GenerateMethodGroup(@group); |
||||||
|
} |
||||||
|
|
||||||
|
public override void GenerateFunctionGroup(List<Function> @group) |
||||||
|
{ |
||||||
|
if (@group.Count > 1) |
||||||
|
{ |
||||||
|
Console.WriteLine($"Ignoring function group: {@group.First().QualifiedOriginalName}"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
base.GenerateFunctionGroup(@group); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitDeclContextFunctions(DeclarationContext context) |
||||||
|
{ |
||||||
|
PushBlock(); |
||||||
|
base.VisitDeclContextFunctions(context); |
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
var prefix = function is Method ? ".function" : "emscripten::function"; |
||||||
|
Write($"{prefix}(\"{function.Name}\", &{function.QualifiedOriginalName}"); |
||||||
|
|
||||||
|
var hasPointers = function.ReturnType.Type.IsPointer() || |
||||||
|
function.Parameters.Any(p => p.Type.IsPointer()); |
||||||
|
if (hasPointers) |
||||||
|
Write(", emscripten::allow_raw_pointers()"); |
||||||
|
|
||||||
|
WriteLine(function is not Method ? ");" : $")"); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEnumDecl(Enumeration @enum) |
||||||
|
{ |
||||||
|
if (@enum.IsIncomplete) |
||||||
|
return false; |
||||||
|
|
||||||
|
PushBlock(); |
||||||
|
|
||||||
|
WriteLine($"emscripten::enum_<{@enum.Name}>(\"{@enum.QualifiedOriginalName}\")"); |
||||||
|
foreach (var item in @enum.Items) |
||||||
|
{ |
||||||
|
WriteLineIndent(@enum.IsScoped |
||||||
|
? $".value(\"{item.Name}\", {@enum.QualifiedOriginalName}::{item.OriginalName})" |
||||||
|
: $".value(\"{item.Name}\", {item.QualifiedOriginalName})"); |
||||||
|
} |
||||||
|
WriteLineIndent(";"); |
||||||
|
|
||||||
|
PopBlock(NewLineKind.BeforeNextBlock); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefDecl(TypedefDecl typedef) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
using CppSharp.Generators.C; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Emscripten |
||||||
|
{ |
||||||
|
public class EmscriptenTypePrinter : CppTypePrinter |
||||||
|
{ |
||||||
|
public EmscriptenTypePrinter(BindingContext context) : base(context) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
|
||||||
|
workspace "emscripten" |
||||||
|
configurations { "debug", "release" } |
||||||
|
location "gen" |
||||||
|
symbols "On" |
||||||
|
optimize "Off" |
||||||
|
|
||||||
|
project "test" |
||||||
|
kind "SharedLib" |
||||||
|
language "C++" |
||||||
|
files |
||||||
|
{ |
||||||
|
"gen/**.cpp", |
||||||
|
} |
||||||
|
includedirs |
||||||
|
{ |
||||||
|
"..", |
||||||
|
"../../include" |
||||||
|
} |
||||||
|
linkoptions { "--bind -sENVIRONMENT=node -sMODULARIZE=1 -sEXPORT_ALL -sEXPORT_ES6=1 -sUSE_ES6_IMPORT_META=1" } |
||||||
|
targetextension ".mjs" |
@ -0,0 +1,114 @@ |
|||||||
|
import wasmModule from "./gen/bin/debug/libtest.mjs"; |
||||||
|
import { eq, ascii, floateq } from "./utils.mjs" |
||||||
|
|
||||||
|
const test = await wasmModule({ |
||||||
|
onRuntimeInitialized() { |
||||||
|
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
function builtins() { |
||||||
|
eq(test.ReturnsVoid(), undefined) |
||||||
|
|
||||||
|
eq(test.ReturnsBool(), true) |
||||||
|
eq(test.PassAndReturnsBool(false), false) |
||||||
|
|
||||||
|
eq(test.ReturnsNullptr(), null) |
||||||
|
eq(test.PassAndReturnsNullptr(null), null) |
||||||
|
|
||||||
|
eq(test.ReturnsChar(), ascii('a')); |
||||||
|
eq(test.ReturnsSChar(), ascii('a')); |
||||||
|
eq(test.ReturnsUChar(), ascii('a')); |
||||||
|
|
||||||
|
eq(test.PassAndReturnsChar(ascii('a')), ascii('a')); |
||||||
|
eq(test.PassAndReturnsSChar(ascii('b')), ascii('b')); |
||||||
|
eq(test.PassAndReturnsUChar(ascii('c')), ascii('c')); |
||||||
|
|
||||||
|
// TODO: add wchar_t tests
|
||||||
|
|
||||||
|
eq(test.ReturnsFloat(), 5.0); |
||||||
|
eq(test.ReturnsDouble(), -5.0); |
||||||
|
//eq(test.ReturnsLongDouble(), -5.0);
|
||||||
|
|
||||||
|
floateq(test.PassAndReturnsFloat(1.32), 1.32); |
||||||
|
floateq(test.PassAndReturnsDouble(1.32), 1.32); |
||||||
|
//float(test.PassAndReturnsLongDouble(1.32), 1.32);
|
||||||
|
|
||||||
|
eq(test.ReturnsInt8(), -5); |
||||||
|
eq(test.ReturnsUInt8(), 5); |
||||||
|
eq(test.ReturnsInt16(), -5); |
||||||
|
eq(test.ReturnsUInt16(), 5); |
||||||
|
eq(test.ReturnsInt32(), -5); |
||||||
|
eq(test.ReturnsUInt32(), 5); |
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// https://github.com/WebAssembly/proposals/issues/7
|
||||||
|
// https://github.com/emscripten-core/emscripten/issues/11140
|
||||||
|
//eq(test.ReturnsInt64(), -5n);
|
||||||
|
//eq(test.ReturnsUInt64(), 5n);
|
||||||
|
|
||||||
|
const int8 = { min: -(2 ** 7), max: (2 ** 7) - 1 }; |
||||||
|
eq(test.PassAndReturnsInt8(int8.min), int8.min); |
||||||
|
eq(test.PassAndReturnsInt8(int8.max), int8.max); |
||||||
|
|
||||||
|
const uint8 = { min: 0, max: (2 ** 8) - 1 }; |
||||||
|
eq(test.PassAndReturnsUInt8(uint8.min), uint8.min); |
||||||
|
eq(test.PassAndReturnsUInt8(uint8.max), uint8.max); |
||||||
|
|
||||||
|
const int16 = { min: -(2 ** 15), max: (2 ** 15) - 1 }; |
||||||
|
eq(test.PassAndReturnsInt16(int16.min), int16.min); |
||||||
|
eq(test.PassAndReturnsInt16(int16.max), int16.max); |
||||||
|
|
||||||
|
const uint16 = { min: 0, max: (2 ** 16) - 1 }; |
||||||
|
eq(test.PassAndReturnsUInt16(uint16.min), uint16.min); |
||||||
|
eq(test.PassAndReturnsUInt16(uint16.max), uint16.max); |
||||||
|
|
||||||
|
const int32 = { min: -(2 ** 31), max: (2 ** 31) - 1 }; |
||||||
|
eq(test.PassAndReturnsInt32(int32.min), int32.min); |
||||||
|
eq(test.PassAndReturnsInt32(int32.max), int32.max); |
||||||
|
|
||||||
|
const uint32 = { min: 0, max: (2 ** 32) - 1 }; |
||||||
|
eq(test.PassAndReturnsUInt32(uint32.min), uint32.min); |
||||||
|
eq(test.PassAndReturnsUInt32(uint32.max), uint32.max); |
||||||
|
|
||||||
|
//const int64 = { min: BigInt(2 ** 63) * -1n, max: BigInt(2 ** 63) - 1n };
|
||||||
|
//eq(test.PassAndReturnsInt64(int64.min), int64.min);
|
||||||
|
//eq(test.PassAndReturnsInt64(int64.max), int64.max);
|
||||||
|
|
||||||
|
//const uint64 = { min: BigInt(0), max: BigInt(2 ** 64) - 1n };
|
||||||
|
//eq(test.PassAndReturnsUInt64(uint64.min), uint64.min);
|
||||||
|
//eq(test.PassAndReturnsUInt64(uint64.max), uint64.max);
|
||||||
|
} |
||||||
|
|
||||||
|
function enums() { |
||||||
|
eq(test.Enum0.Item0.value, 0); |
||||||
|
eq(test.Enum0.Item1.value, 1); |
||||||
|
eq(test.Enum0.Item2.value, 5); |
||||||
|
|
||||||
|
eq(test.ReturnsEnum(), test.Enum0.Item0); |
||||||
|
eq(test.PassAndReturnsEnum(test.Enum0.Item1), test.Enum0.Item1); |
||||||
|
} |
||||||
|
|
||||||
|
function classes() { |
||||||
|
var c = new test.Class(); |
||||||
|
eq(typeof (c), "object") |
||||||
|
eq(c.ReturnsVoid(), undefined) |
||||||
|
eq(c.ReturnsInt(), 0) |
||||||
|
eq(c.PassAndReturnsClassPtr(null), null) |
||||||
|
|
||||||
|
var c1 = new test.ClassWithSingleInheritance(); |
||||||
|
eq(c1.__proto__.constructor.name, 'ClassWithSingleInheritance') |
||||||
|
eq(c1.__proto__.__proto__.constructor.name, 'Class') |
||||||
|
eq(c1.ReturnsVoid(), undefined); |
||||||
|
eq(c1.ReturnsInt(), 0); |
||||||
|
eq(c1.ChildMethod(), 2); |
||||||
|
|
||||||
|
var classWithField = new test.ClassWithField(); |
||||||
|
eq(classWithField.ReturnsField(), 10); |
||||||
|
eq(classWithField.Field, 10); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
builtins(); |
||||||
|
enums(); |
||||||
|
classes(); |
@ -0,0 +1,30 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
set -e |
||||||
|
dir=$(cd "$(dirname "$0")"; pwd) |
||||||
|
rootdir="$dir/../.." |
||||||
|
dotnet_configuration=Release |
||||||
|
configuration=debug |
||||||
|
platform=x64 |
||||||
|
jsinterp=node |
||||||
|
|
||||||
|
red=`tput setaf 1` |
||||||
|
green=`tput setaf 2` |
||||||
|
reset=`tput sgr0` |
||||||
|
|
||||||
|
generate=true |
||||||
|
|
||||||
|
if [ $generate = true ]; then |
||||||
|
echo "${green}Generating bindings${reset}" |
||||||
|
dotnet $rootdir/bin/${dotnet_configuration}_${platform}/CppSharp.CLI.dll \ |
||||||
|
--gen=emscripten --platform=emscripten --arch=wasm32 \ |
||||||
|
-I$dir/.. -I$rootdir/include -o $dir/gen -m tests $dir/../*.h |
||||||
|
fi |
||||||
|
|
||||||
|
echo "${green}Building generated binding files${reset}" |
||||||
|
premake=$rootdir/build/premake.sh |
||||||
|
config=$configuration $premake --file=$dir/premake5.lua gmake |
||||||
|
emmake make -C $dir/gen |
||||||
|
echo |
||||||
|
|
||||||
|
echo "${green}Executing JS tests with Node${reset}" |
||||||
|
$jsinterp $dir/test.mjs |
@ -0,0 +1,21 @@ |
|||||||
|
export function assert(actual, expected, message) { |
||||||
|
if (arguments.length == 1) |
||||||
|
expected = true; |
||||||
|
|
||||||
|
if (actual === expected) |
||||||
|
return; |
||||||
|
|
||||||
|
if (actual !== null && expected !== null |
||||||
|
&& typeof actual == 'object' && typeof expected == 'object' |
||||||
|
&& actual.toString() === expected.toString()) |
||||||
|
return; |
||||||
|
|
||||||
|
throw Error("assertion failed: got |" + actual + "|" + |
||||||
|
", expected |" + expected + "|" + |
||||||
|
(message ? " (" + message + ")" : "")); |
||||||
|
} |
||||||
|
|
||||||
|
export const eq = assert; |
||||||
|
export const floateq = (actual, expected) => { assert(Math.abs(actual - expected) < 0.01) } |
||||||
|
|
||||||
|
export const ascii = v => v.charCodeAt(0) |
Loading…
Reference in new issue