mirror of https://github.com/mono/CppSharp.git
11 changed files with 1219 additions and 0 deletions
@ -0,0 +1,8 @@ |
|||||||
|
set -ex |
||||||
|
mono ../../build/vs2015/lib/Debug_x64/CppSharp.CLI.exe -gen=qjs -module=test -prefix=js_ test-native.h |
||||||
|
../../build/premake5-osx --file=premake5.lua gmake |
||||||
|
make clean |
||||||
|
make |
||||||
|
|
||||||
|
cp gen/bin/release/libtest.dylib . |
||||||
|
../../deps/QuickJS/qjs test.js |
@ -0,0 +1,15 @@ |
|||||||
|
qjs_inc_dir = path.getabsolute("../../deps/QuickJS") |
||||||
|
qjs_lib_dir = path.getabsolute("../../deps/QuickJS") |
||||||
|
|
||||||
|
workspace "qjs" |
||||||
|
configurations { "release" } |
||||||
|
|
||||||
|
project "test-native" |
||||||
|
kind "StaticLib" |
||||||
|
files { "*-native.cpp" } |
||||||
|
|
||||||
|
include "gen/js_premake5.lua" |
||||||
|
|
||||||
|
project "test" |
||||||
|
includedirs { "." } |
||||||
|
links { "test-native" } |
@ -0,0 +1,6 @@ |
|||||||
|
#include "test-native.h" |
||||||
|
|
||||||
|
extern "C" int plus(int a, int b) |
||||||
|
{ |
||||||
|
return a + b; |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
import { plus } from './libtest.dylib' |
||||||
|
console.log(plus(1, 2)) |
@ -0,0 +1,150 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.Cpp; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.C |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// QuickJS generator responsible for driving the generation of binding files.
|
||||||
|
/// QuickJS documentation: https://bellard.org/quickjs/
|
||||||
|
/// </summary>
|
||||||
|
public class QuickJSGenerator : CppGenerator |
||||||
|
{ |
||||||
|
public QuickJSGenerator(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); |
||||||
|
} |
||||||
|
|
||||||
|
var premake = GeneratePremake(module); |
||||||
|
if (premake != null) |
||||||
|
{ |
||||||
|
OnUnitGenerated(premake); |
||||||
|
outputs.Add(premake); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return outputs; |
||||||
|
} |
||||||
|
|
||||||
|
public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units) |
||||||
|
{ |
||||||
|
var outputs = new List<CodeGenerator>(); |
||||||
|
|
||||||
|
var header = new QuickJSHeaders(Context, units); |
||||||
|
outputs.Add(header); |
||||||
|
|
||||||
|
var source = new QuickJSSources(Context, units); |
||||||
|
outputs.Add(source); |
||||||
|
|
||||||
|
return outputs; |
||||||
|
} |
||||||
|
|
||||||
|
public override GeneratorOutput GenerateModule(Module module) |
||||||
|
{ |
||||||
|
if (module == Context.Options.SystemModule) |
||||||
|
return null; |
||||||
|
|
||||||
|
var moduleGen = new QuickJSModule(Context, module); |
||||||
|
|
||||||
|
var output = new GeneratorOutput |
||||||
|
{ |
||||||
|
TranslationUnit = new TranslationUnit |
||||||
|
{ |
||||||
|
FilePath = $"{module.LibraryName}_qjs_module.cpp", |
||||||
|
Module = module |
||||||
|
}, |
||||||
|
Outputs = new List<CodeGenerator> { moduleGen } |
||||||
|
}; |
||||||
|
|
||||||
|
output.Outputs[0].Process(); |
||||||
|
|
||||||
|
return output; |
||||||
|
} |
||||||
|
|
||||||
|
public GeneratorOutput GeneratePremake(Module module) |
||||||
|
{ |
||||||
|
if (module == Context.Options.SystemModule) |
||||||
|
return null; |
||||||
|
|
||||||
|
var premakeGen = new QuickJSPremakeBuildGenerator(Context, module); |
||||||
|
|
||||||
|
var output = new GeneratorOutput |
||||||
|
{ |
||||||
|
TranslationUnit = new TranslationUnit |
||||||
|
{ |
||||||
|
FilePath = "premake5.lua", |
||||||
|
Module = module |
||||||
|
}, |
||||||
|
Outputs = new List<CodeGenerator> { premakeGen } |
||||||
|
}; |
||||||
|
|
||||||
|
output.Outputs[0].Process(); |
||||||
|
|
||||||
|
return output; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class QuickJSPremakeBuildGenerator : CodeGenerator |
||||||
|
{ |
||||||
|
readonly Module module; |
||||||
|
|
||||||
|
public QuickJSPremakeBuildGenerator(BindingContext context, Module module) |
||||||
|
: base(context, (TranslationUnit)null) |
||||||
|
{ |
||||||
|
this.module = module; |
||||||
|
} |
||||||
|
|
||||||
|
public override string FileExtension => "lua"; |
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
/* |
||||||
|
var qjsPath = @"/Users/joao/Dev/CppSharp/examples/wxSharp/QuickJS"; |
||||||
|
WriteLine($"qjs_inc_dir = \"{qjsPath}\""); |
||||||
|
WriteLine($"qjs_lib_dir = \"{qjsPath}\""); |
||||||
|
|
||||||
|
WriteLine("workspace \"qjs\""); |
||||||
|
WriteLineIndent("configurations { \"release\" }"); |
||||||
|
*/ |
||||||
|
|
||||||
|
WriteLine($"project \"{module.LibraryName}\""); |
||||||
|
Indent(); |
||||||
|
|
||||||
|
WriteLine("kind \"SharedLib\""); |
||||||
|
WriteLine("language \"C++\""); |
||||||
|
WriteLine("files { \"*.cpp\" }"); |
||||||
|
WriteLine("includedirs { qjs_inc_dir }"); |
||||||
|
WriteLine("libdirs { qjs_lib_dir }"); |
||||||
|
WriteLine("filter { \"kind:StaticLib\" }"); |
||||||
|
WriteLineIndent("links { \"quickjs\" }"); |
||||||
|
WriteLine("filter { \"kind:SharedLib\" }"); |
||||||
|
WriteLineIndent("defines { \"JS_SHARED_LIBRARY\" }"); |
||||||
|
WriteLine("filter { \"kind:SharedLib\", \"system:macosx\" }"); |
||||||
|
WriteLineIndent("linkoptions { \"-undefined dynamic_lookup\" }"); |
||||||
|
|
||||||
|
Unindent(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* TODO: Write a build.sh aswell. |
||||||
|
* set -ex |
||||||
|
../../../../../build/premake5-osx gmake |
||||||
|
make clean |
||||||
|
make |
||||||
|
*/ |
||||||
|
} |
@ -0,0 +1,51 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Generates QuickJS C/C++ header files.
|
||||||
|
/// QuickJS documentation: https://bellard.org/quickjs/
|
||||||
|
/// </summary>
|
||||||
|
public class QuickJSHeaders : CppHeaders |
||||||
|
{ |
||||||
|
public QuickJSHeaders(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(); |
||||||
|
|
||||||
|
var include = new CInclude() |
||||||
|
{ |
||||||
|
File = "quickjs.h", |
||||||
|
Kind = CInclude.IncludeKind.Angled |
||||||
|
}; |
||||||
|
|
||||||
|
WriteInclude(include); |
||||||
|
NewLine(); |
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
VisitNamespace(TranslationUnit); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
Write("extern \"C\" "); |
||||||
|
WriteLine($"JSValue js_{function.Name}(JSContext* ctx, JSValueConst this_val,"); |
||||||
|
WriteLineIndent("int argc, JSValueConst* argv);"); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,721 @@ |
|||||||
|
using System; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.AST.Extensions; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
using CppSharp.Generators.CLI; |
||||||
|
using CppSharp.Types; |
||||||
|
using Delegate = CppSharp.AST.Delegate; |
||||||
|
using Type = CppSharp.AST.Type; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
public class QuickJSMarshalNativeToManagedPrinter : MarshalPrinter<MarshalContext> |
||||||
|
{ |
||||||
|
public QuickJSMarshalNativeToManagedPrinter(MarshalContext marshalContext) |
||||||
|
: base(marshalContext) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public string MemoryAllocOperator => |
||||||
|
(Context.Context.Options.GeneratorKind == GeneratorKind.CLI) ? |
||||||
|
"gcnew" : "new"; |
||||||
|
|
||||||
|
public override bool VisitType(Type type, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(type, out typeMap) && typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.MarshalToManaged(GeneratorKind.QuickJS, Context); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitArrayType(ArrayType array, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
switch (array.SizeType) |
||||||
|
{ |
||||||
|
case ArrayType.ArraySize.Constant: |
||||||
|
case ArrayType.ArraySize.Incomplete: |
||||||
|
case ArrayType.ArraySize.Variable: |
||||||
|
Context.Return.Write("nullptr"); |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new System.NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
Context.Return.Write(Context.ReturnVarName); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (!VisitType(pointer, quals)) |
||||||
|
return false; |
||||||
|
|
||||||
|
var pointee = pointer.Pointee.Desugar(); |
||||||
|
|
||||||
|
PrimitiveType primitive; |
||||||
|
var param = Context.Parameter; |
||||||
|
if (param != null && (param.IsOut || param.IsInOut) && |
||||||
|
pointee.IsPrimitiveType(out primitive)) |
||||||
|
{ |
||||||
|
Context.Return.Write(Context.ReturnVarName); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
if (pointee.IsPrimitiveType(out primitive)) |
||||||
|
{ |
||||||
|
var returnVarName = Context.ReturnVarName; |
||||||
|
|
||||||
|
if (pointer.GetFinalQualifiedPointee().Qualifiers.IsConst != |
||||||
|
Context.ReturnType.Qualifiers.IsConst) |
||||||
|
{ |
||||||
|
var nativeTypePrinter = new CppTypePrinter(Context.Context) |
||||||
|
{ PrintTypeQualifiers = false }; |
||||||
|
var returnType = Context.ReturnType.Type.Desugar(); |
||||||
|
var constlessPointer = new PointerType() |
||||||
|
{ |
||||||
|
IsDependent = pointer.IsDependent, |
||||||
|
Modifier = pointer.Modifier, |
||||||
|
QualifiedPointee = new QualifiedType(returnType.GetPointee()) |
||||||
|
}; |
||||||
|
var nativeConstlessTypeName = constlessPointer.Visit(nativeTypePrinter, new TypeQualifiers()); |
||||||
|
returnVarName = string.Format("const_cast<{0}>({1})", |
||||||
|
nativeConstlessTypeName, Context.ReturnVarName); |
||||||
|
} |
||||||
|
|
||||||
|
if (pointer.Pointee is TypedefType) |
||||||
|
{ |
||||||
|
var desugaredPointer = new PointerType() |
||||||
|
{ |
||||||
|
IsDependent = pointer.IsDependent, |
||||||
|
Modifier = pointer.Modifier, |
||||||
|
QualifiedPointee = new QualifiedType(pointee) |
||||||
|
}; |
||||||
|
var nativeTypePrinter = new CppTypePrinter(Context.Context); |
||||||
|
var nativeTypeName = desugaredPointer.Visit(nativeTypePrinter, quals); |
||||||
|
Context.Return.Write("reinterpret_cast<{0}>({1})", nativeTypeName, |
||||||
|
returnVarName); |
||||||
|
} |
||||||
|
else |
||||||
|
Context.Return.Write(returnVarName); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
TypeMap typeMap = null; |
||||||
|
Context.Context.TypeMaps.FindTypeMap(pointee, out typeMap); |
||||||
|
|
||||||
|
Class @class; |
||||||
|
if (pointee.TryGetClass(out @class) && typeMap == null) |
||||||
|
{ |
||||||
|
var instance = (pointer.IsReference) ? "&" + Context.ReturnVarName |
||||||
|
: Context.ReturnVarName; |
||||||
|
WriteClassInstance(@class, instance); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return pointer.QualifiedPointee.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMemberPointerType(MemberPointerType member, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return VisitPrimitiveType(builtin.Type); |
||||||
|
} |
||||||
|
|
||||||
|
public bool VisitPrimitiveType(PrimitiveType primitive) |
||||||
|
{ |
||||||
|
var retName = Generator.GeneratedIdentifier(Context.ArgName); |
||||||
|
Context.Before.Write($"JSValue {retName} = "); |
||||||
|
|
||||||
|
switch (primitive) |
||||||
|
{ |
||||||
|
case PrimitiveType.Void: |
||||||
|
return true; |
||||||
|
case PrimitiveType.Bool: |
||||||
|
case PrimitiveType.Char: |
||||||
|
case PrimitiveType.Char16: |
||||||
|
case PrimitiveType.WideChar: |
||||||
|
case PrimitiveType.SChar: |
||||||
|
case PrimitiveType.UChar: |
||||||
|
case PrimitiveType.Short: |
||||||
|
case PrimitiveType.UShort: |
||||||
|
case PrimitiveType.Int: |
||||||
|
case PrimitiveType.UInt: |
||||||
|
Context.Before.WriteLine($"JS_NewInt32(ctx, {Context.ArgName});"); |
||||||
|
break; |
||||||
|
case PrimitiveType.Long: |
||||||
|
case PrimitiveType.ULong: |
||||||
|
case PrimitiveType.LongLong: |
||||||
|
case PrimitiveType.ULongLong: |
||||||
|
case PrimitiveType.Float: |
||||||
|
case PrimitiveType.Double: |
||||||
|
case PrimitiveType.LongDouble: |
||||||
|
case PrimitiveType.Null: |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
Context.Return.Write(retName); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var decl = typedef.Declaration; |
||||||
|
|
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(decl.Type, out typeMap) && |
||||||
|
typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.Type = typedef; |
||||||
|
typeMap.MarshalToManaged(GeneratorKind.QuickJS, Context); |
||||||
|
return typeMap.IsValueType; |
||||||
|
} |
||||||
|
|
||||||
|
FunctionType function; |
||||||
|
if (decl.Type.IsPointerTo(out function)) |
||||||
|
{ |
||||||
|
var typePrinter = new CppTypePrinter(Context.Context); |
||||||
|
var typeName = typePrinter.VisitDeclaration(decl); |
||||||
|
var typeName2 = decl.Type.Visit(typePrinter); |
||||||
|
Context.Return.Write(typeName); |
||||||
|
//return typeName;
|
||||||
|
//throw new System.NotImplementedException();
|
||||||
|
} |
||||||
|
|
||||||
|
return decl.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTemplateSpecializationType(TemplateSpecializationType template, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(template, out typeMap) && typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.Type = template; |
||||||
|
typeMap.MarshalToManaged(GeneratorKind.QuickJS, Context); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return template.Template.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTemplateParameterType(TemplateParameterType param, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitDeclaration(Declaration decl, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (@class.CompleteDeclaration != null) |
||||||
|
return VisitClassDecl(@class.CompleteDeclaration as Class); |
||||||
|
|
||||||
|
var instance = string.Empty; |
||||||
|
|
||||||
|
if (Context.Context.Options.GeneratorKind == GeneratorKind.CLI) |
||||||
|
{ |
||||||
|
if (!Context.ReturnType.Type.IsPointer()) |
||||||
|
instance += "&"; |
||||||
|
} |
||||||
|
|
||||||
|
instance += Context.ReturnVarName; |
||||||
|
var needsCopy = Context.MarshalKind != MarshalKind.NativeField; |
||||||
|
|
||||||
|
if (@class.IsRefType && needsCopy) |
||||||
|
{ |
||||||
|
var name = Generator.GeneratedIdentifier(Context.ReturnVarName); |
||||||
|
Context.Before.WriteLine($"auto {name} = {MemoryAllocOperator} ::{{0}}({{1}});", |
||||||
|
@class.QualifiedOriginalName, Context.ReturnVarName); |
||||||
|
instance = name; |
||||||
|
} |
||||||
|
|
||||||
|
WriteClassInstance(@class, instance); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public string QualifiedIdentifier(Declaration decl) |
||||||
|
{ |
||||||
|
if (!string.IsNullOrEmpty(decl.TranslationUnit.Module.OutputNamespace)) |
||||||
|
return $"{decl.TranslationUnit.Module.OutputNamespace}::{decl.QualifiedName}"; |
||||||
|
|
||||||
|
return decl.QualifiedName; |
||||||
|
} |
||||||
|
|
||||||
|
public void WriteClassInstance(Class @class, string instance) |
||||||
|
{ |
||||||
|
if (@class.CompleteDeclaration != null) |
||||||
|
{ |
||||||
|
WriteClassInstance(@class.CompleteDeclaration as Class, instance); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (!Context.ReturnType.Type.Desugar().IsPointer()) |
||||||
|
{ |
||||||
|
Context.Return.Write($"{instance}"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (@class.IsRefType) |
||||||
|
Context.Return.Write($"({instance} == nullptr) ? nullptr : {MemoryAllocOperator} "); |
||||||
|
|
||||||
|
Context.Return.Write($"{QualifiedIdentifier(@class)}("); |
||||||
|
Context.Return.Write($"(::{@class.QualifiedOriginalName}*)"); |
||||||
|
Context.Return.Write($"{instance})"); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFieldDecl(Field field) |
||||||
|
{ |
||||||
|
return field.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMethodDecl(Method method) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitParameterDecl(Parameter parameter) |
||||||
|
{ |
||||||
|
Context.Parameter = parameter; |
||||||
|
var ret = parameter.Type.Visit(this, parameter.QualifiedType.Qualifiers); |
||||||
|
Context.Parameter = null; |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefDecl(TypedefDecl typedef) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEnumDecl(Enumeration @enum) |
||||||
|
{ |
||||||
|
var typePrinter = new CppTypePrinter(Context.Context); |
||||||
|
typePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
var typeName = typePrinter.VisitDeclaration(@enum); |
||||||
|
Context.Return.Write($"({typeName}){Context.ReturnVarName}"); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitVariableDecl(Variable variable) |
||||||
|
{ |
||||||
|
return variable.Type.Visit(this, variable.QualifiedType.Qualifiers); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassTemplateDecl(ClassTemplate template) |
||||||
|
{ |
||||||
|
return template.TemplatedClass.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionTemplateDecl(FunctionTemplate template) |
||||||
|
{ |
||||||
|
return template.TemplatedFunction.Visit(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class QuickJSMarshalManagedToNativePrinter : MarshalPrinter<MarshalContext> |
||||||
|
{ |
||||||
|
public readonly TextGenerator VarPrefix; |
||||||
|
public readonly TextGenerator ArgumentPrefix; |
||||||
|
|
||||||
|
public QuickJSMarshalManagedToNativePrinter(MarshalContext ctx) |
||||||
|
: base(ctx) |
||||||
|
{ |
||||||
|
VarPrefix = new TextGenerator(); |
||||||
|
ArgumentPrefix = new TextGenerator(); |
||||||
|
|
||||||
|
Context.MarshalToNative = this; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitType(Type type, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(type, out typeMap) && typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.MarshalToNative(GeneratorKind.QuickJS, Context); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTagType(TagType tag, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (!VisitType(tag, quals)) |
||||||
|
return false; |
||||||
|
|
||||||
|
return tag.Declaration.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitArrayType(ArrayType array, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (!VisitType(array, quals)) |
||||||
|
return false; |
||||||
|
|
||||||
|
switch (array.SizeType) |
||||||
|
{ |
||||||
|
default: |
||||||
|
Context.Return.Write("nullptr"); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var returnType = function.ReturnType; |
||||||
|
return returnType.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public bool VisitDelegateType(string type) |
||||||
|
{ |
||||||
|
Context.Return.Write(Context.Parameter.Name); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
if (!VisitType(pointer, quals)) |
||||||
|
return false; |
||||||
|
|
||||||
|
var pointee = pointer.Pointee.Desugar(); |
||||||
|
|
||||||
|
if (pointee is FunctionType) |
||||||
|
{ |
||||||
|
var cppTypePrinter = new CppTypePrinter(Context.Context); |
||||||
|
cppTypePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
var cppTypeName = pointer.Visit(cppTypePrinter, quals); |
||||||
|
|
||||||
|
return VisitDelegateType(cppTypeName); |
||||||
|
} |
||||||
|
|
||||||
|
Enumeration @enum; |
||||||
|
if (pointee.TryGetEnum(out @enum)) |
||||||
|
{ |
||||||
|
var isRef = Context.Parameter.Usage == ParameterUsage.Out || |
||||||
|
Context.Parameter.Usage == ParameterUsage.InOut; |
||||||
|
|
||||||
|
ArgumentPrefix.Write("&"); |
||||||
|
Context.Return.Write($"(::{@enum.QualifiedOriginalName}){0}{Context.Parameter.Name}", |
||||||
|
isRef ? string.Empty : "*"); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
Class @class; |
||||||
|
if (pointee.TryGetClass(out @class) && @class.IsValueType) |
||||||
|
{ |
||||||
|
if (Context.Function == null) |
||||||
|
Context.Return.Write("&"); |
||||||
|
return pointer.QualifiedPointee.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
var finalPointee = pointer.GetFinalPointee(); |
||||||
|
if (finalPointee.IsPrimitiveType()) |
||||||
|
{ |
||||||
|
var cppTypePrinter = new CppTypePrinter(Context.Context); |
||||||
|
var cppTypeName = pointer.Visit(cppTypePrinter, quals); |
||||||
|
|
||||||
|
Context.Return.Write($"({cppTypeName})"); |
||||||
|
Context.Return.Write(Context.Parameter.Name); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return pointer.QualifiedPointee.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMemberPointerType(MemberPointerType member, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
return VisitPrimitiveType(builtin.Type); |
||||||
|
} |
||||||
|
|
||||||
|
public bool VisitPrimitiveType(PrimitiveType primitive) |
||||||
|
{ |
||||||
|
var typePrinter = new CppTypePrinter(Context.Context); |
||||||
|
var type = typePrinter.VisitPrimitiveType(primitive); |
||||||
|
|
||||||
|
Context.Before.WriteLine($"{type} {Context.ArgName};"); |
||||||
|
|
||||||
|
switch (primitive) |
||||||
|
{ |
||||||
|
case PrimitiveType.Void: |
||||||
|
return true; |
||||||
|
case PrimitiveType.Bool: |
||||||
|
//JS_ToBool
|
||||||
|
case PrimitiveType.Char: |
||||||
|
case PrimitiveType.UChar: |
||||||
|
case PrimitiveType.Short: |
||||||
|
case PrimitiveType.UShort: |
||||||
|
case PrimitiveType.Int: |
||||||
|
Context.Before.WriteLine($"if (JS_ToInt32(ctx, &{Context.ArgName}, argv[{Context.ParameterIndex}]))"); |
||||||
|
Context.Before.WriteLineIndent("return JS_EXCEPTION;"); |
||||||
|
return true; |
||||||
|
case PrimitiveType.UInt: |
||||||
|
case PrimitiveType.Long: |
||||||
|
case PrimitiveType.ULong: |
||||||
|
case PrimitiveType.LongLong: |
||||||
|
case PrimitiveType.ULongLong: |
||||||
|
case PrimitiveType.Float: |
||||||
|
case PrimitiveType.Double: |
||||||
|
case PrimitiveType.WideChar: |
||||||
|
default: |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
var decl = typedef.Declaration; |
||||||
|
|
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(decl.Type, out typeMap) && |
||||||
|
typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.MarshalToNative(GeneratorKind.QuickJS, Context); |
||||||
|
return typeMap.IsValueType; |
||||||
|
} |
||||||
|
|
||||||
|
FunctionType func; |
||||||
|
if (decl.Type.IsPointerTo(out func)) |
||||||
|
{ |
||||||
|
var typePrinter = new CppTypePrinter(Context.Context); |
||||||
|
typePrinter.PushContext(TypePrinterContextKind.Native); |
||||||
|
var declName = decl.Visit(typePrinter); |
||||||
|
typePrinter.PopContext(); |
||||||
|
|
||||||
|
// Use the original typedef name if available, otherwise just use the function pointer type
|
||||||
|
string cppTypeName; |
||||||
|
if (!decl.IsSynthetized) |
||||||
|
{ |
||||||
|
cppTypeName = "::" + typedef.Declaration.QualifiedOriginalName; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
cppTypeName = decl.Type.Visit(typePrinter, quals); |
||||||
|
} |
||||||
|
|
||||||
|
VisitDelegateType(cppTypeName); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
PrimitiveType primitive; |
||||||
|
if (decl.Type.IsPrimitiveType(out primitive)) |
||||||
|
{ |
||||||
|
Context.Return.Write($"(::{typedef.Declaration.QualifiedOriginalName})"); |
||||||
|
} |
||||||
|
|
||||||
|
return decl.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTemplateSpecializationType(TemplateSpecializationType template, |
||||||
|
TypeQualifiers quals) |
||||||
|
{ |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(template, out typeMap) && typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.Type = template; |
||||||
|
typeMap.MarshalToNative(GeneratorKind.QuickJS, Context); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return template.Template.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTemplateParameterType(TemplateParameterType param, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
Context.Return.Write(param.Parameter.Name); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitDeclaration(Declaration decl, TypeQualifiers quals) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassDecl(Class @class) |
||||||
|
{ |
||||||
|
if (@class.CompleteDeclaration != null) |
||||||
|
return VisitClassDecl(@class.CompleteDeclaration as Class); |
||||||
|
|
||||||
|
if (@class.IsValueType) |
||||||
|
{ |
||||||
|
MarshalValueClass(@class); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
MarshalRefClass(@class); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private void MarshalRefClass(Class @class) |
||||||
|
{ |
||||||
|
var type = Context.Parameter.Type.Desugar(); |
||||||
|
TypeMap typeMap; |
||||||
|
if (Context.Context.TypeMaps.FindTypeMap(type, out typeMap) && |
||||||
|
typeMap.DoesMarshalling) |
||||||
|
{ |
||||||
|
typeMap.MarshalToNative(GeneratorKind.QuickJS, Context); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (!type.SkipPointerRefs().IsPointer()) |
||||||
|
{ |
||||||
|
Context.Return.Write("*"); |
||||||
|
|
||||||
|
if (Context.Parameter.Type.IsReference()) |
||||||
|
VarPrefix.Write("&"); |
||||||
|
} |
||||||
|
|
||||||
|
var method = Context.Function as Method; |
||||||
|
if (method != null |
||||||
|
&& method.Conversion == MethodConversionKind.FunctionToInstanceMethod |
||||||
|
&& Context.ParameterIndex == 0) |
||||||
|
{ |
||||||
|
Context.Return.Write($"(::{@class.QualifiedOriginalName}*)"); |
||||||
|
Context.Return.Write(Helpers.InstanceIdentifier); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var paramType = Context.Parameter.Type.Desugar(); |
||||||
|
var isPointer = paramType.SkipPointerRefs().IsPointer(); |
||||||
|
var deref = isPointer ? "->" : "."; |
||||||
|
var instance = $"(::{@class.QualifiedOriginalName}*)" + |
||||||
|
$"{Context.Parameter.Name}{deref}{Helpers.InstanceIdentifier}"; |
||||||
|
|
||||||
|
if (isPointer) |
||||||
|
Context.Return.Write($"{Context.Parameter.Name} ? {instance} : nullptr"); |
||||||
|
else |
||||||
|
Context.Return.Write($"{instance}"); |
||||||
|
} |
||||||
|
|
||||||
|
private void MarshalValueClass(Class @class) |
||||||
|
{ |
||||||
|
throw new System.NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFieldDecl(Field field) |
||||||
|
{ |
||||||
|
Context.Parameter = new Parameter |
||||||
|
{ |
||||||
|
Name = Context.ArgName, |
||||||
|
QualifiedType = field.QualifiedType |
||||||
|
}; |
||||||
|
|
||||||
|
return field.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitProperty(Property property) |
||||||
|
{ |
||||||
|
Context.Parameter = new Parameter |
||||||
|
{ |
||||||
|
Name = Context.ArgName, |
||||||
|
QualifiedType = property.QualifiedType |
||||||
|
}; |
||||||
|
|
||||||
|
return base.VisitProperty(property); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMethodDecl(Method method) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitParameterDecl(Parameter parameter) |
||||||
|
{ |
||||||
|
return parameter.Type.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTypedefDecl(TypedefDecl typedef) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEnumDecl(Enumeration @enum) |
||||||
|
{ |
||||||
|
Context.Return.Write("(::{0}){1}", @enum.QualifiedOriginalName, |
||||||
|
Context.Parameter.Name); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitVariableDecl(Variable variable) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitClassTemplateDecl(ClassTemplate template) |
||||||
|
{ |
||||||
|
return template.TemplatedClass.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionTemplateDecl(FunctionTemplate template) |
||||||
|
{ |
||||||
|
return template.TemplatedFunction.Visit(this); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitMacroDefinition(MacroDefinition macro) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitNamespace(Namespace @namespace) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitEvent(Event @event) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
|
||||||
|
public bool VisitDelegate(Delegate @delegate) |
||||||
|
{ |
||||||
|
throw new NotImplementedException(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,141 @@ |
|||||||
|
using System.IO; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Generates QuickJS C/C++ module init files.
|
||||||
|
/// QuickJS documentation: https://bellard.org/quickjs/
|
||||||
|
/// </summary>
|
||||||
|
public class QuickJSModule : CCodeGenerator |
||||||
|
{ |
||||||
|
readonly Module module; |
||||||
|
|
||||||
|
public QuickJSModule(BindingContext context, Module module) |
||||||
|
: base(context, module.Units.GetGenerated()) |
||||||
|
{ |
||||||
|
this.module = module; |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
} |
||||||
|
|
||||||
|
public override string FileExtension { get; } = "cpp"; |
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
GenerateFilePreamble(CommentKind.BCPL); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Includes); |
||||||
|
|
||||||
|
WriteInclude(new CInclude() |
||||||
|
{ |
||||||
|
File = "quickjs.h", |
||||||
|
Kind = CInclude.IncludeKind.Angled |
||||||
|
}); |
||||||
|
|
||||||
|
foreach (var unit in TranslationUnits) |
||||||
|
{ |
||||||
|
WriteInclude(new CInclude() |
||||||
|
{ |
||||||
|
File = GetIncludeFileName(Context, unit), |
||||||
|
Kind = CInclude.IncludeKind.Quoted |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
NewLine(); |
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
WriteLine("#define countof(x) (sizeof(x) / sizeof((x)[0]))"); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
var moduleName = module.LibraryName; |
||||||
|
|
||||||
|
// Generate JS module function list.
|
||||||
|
WriteLine($"static const JSCFunctionListEntry js_{moduleName}_funcs[] ="); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
// Foreach translation unit, write the generated functions.
|
||||||
|
foreach (var unit in TranslationUnits) |
||||||
|
{ |
||||||
|
var functionPrinter = new QuickJSModuleFunctionPrinter(Context); |
||||||
|
functionPrinter.Indent(CurrentIndentation); |
||||||
|
unit.Visit(functionPrinter); |
||||||
|
|
||||||
|
Write(functionPrinter.Generate()); |
||||||
|
} |
||||||
|
|
||||||
|
Unindent(); |
||||||
|
WriteLine("};"); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
// Generate init function.
|
||||||
|
WriteLine($"static int js_{moduleName}_init(JSContext* ctx, JSModuleDef* m)"); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
WriteLine($"return JS_SetModuleExportList(ctx, m, js_{moduleName}_funcs," + |
||||||
|
$" countof(js_{moduleName}_funcs));"); |
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
// Generate module initializer.
|
||||||
|
WriteLine("#ifdef JS_SHARED_LIBRARY"); |
||||||
|
WriteLine("#define JS_INIT_MODULE js_init_module"); |
||||||
|
WriteLine("#else"); |
||||||
|
WriteLine($"#define JS_INIT_MODULE js_init_module_{moduleName}"); |
||||||
|
WriteLine("#endif"); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
Write("extern \"C\" "); |
||||||
|
WriteLine("JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)"); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
WriteLine("JSModuleDef* m;"); |
||||||
|
WriteLine($"m = JS_NewCModule(ctx, module_name, js_{moduleName}_init);"); |
||||||
|
WriteLine("if (!m)"); |
||||||
|
WriteLineIndent("return NULL;"); |
||||||
|
NewLine(); |
||||||
|
|
||||||
|
WriteLine($"JS_AddModuleExportList(ctx, m, js_{moduleName}_funcs," + |
||||||
|
$" countof(js_{moduleName}_funcs));"); |
||||||
|
WriteLine("return m;"); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
} |
||||||
|
|
||||||
|
public static string GetIncludeFileName(BindingContext context, |
||||||
|
TranslationUnit unit) |
||||||
|
{ |
||||||
|
string file; |
||||||
|
if (context.Options.GenerateName != null) |
||||||
|
file = context.Options.GenerateName(unit); |
||||||
|
else |
||||||
|
file = Path.GetFileNameWithoutExtension(unit.FileName) |
||||||
|
.Replace('\\', '/'); |
||||||
|
|
||||||
|
return $"{file}.h"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class QuickJSModuleFunctionPrinter : CCodeGenerator |
||||||
|
{ |
||||||
|
public QuickJSModuleFunctionPrinter(BindingContext context) |
||||||
|
: base(context, null) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitTranslationUnit(TranslationUnit unit) |
||||||
|
{ |
||||||
|
WriteLine($"// {QuickJSModule.GetIncludeFileName(Context, unit)}"); |
||||||
|
|
||||||
|
return base.VisitTranslationUnit(unit); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
WriteLine($"JS_CFUNC_DEF(\"{function.Name}\"," + |
||||||
|
$" {function.Parameters.Count}, js_{function.Name}),"); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,115 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.IO; |
||||||
|
using CppSharp.AST; |
||||||
|
using CppSharp.Generators.C; |
||||||
|
|
||||||
|
namespace CppSharp.Generators.Cpp |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Generates QuickJS C/C++ source files.
|
||||||
|
/// QuickJS documentation: https://bellard.org/quickjs/
|
||||||
|
/// </summary>
|
||||||
|
public class QuickJSSources : CppSources |
||||||
|
{ |
||||||
|
public QuickJSSources(BindingContext context, IEnumerable<TranslationUnit> units) |
||||||
|
: base(context, units) |
||||||
|
{ |
||||||
|
CTypePrinter.PushContext(TypePrinterContextKind.Managed); |
||||||
|
} |
||||||
|
|
||||||
|
public override void Process() |
||||||
|
{ |
||||||
|
GenerateFilePreamble(CommentKind.BCPL); |
||||||
|
|
||||||
|
PushBlock(BlockKind.Includes); |
||||||
|
|
||||||
|
WriteInclude(new CInclude() |
||||||
|
{ |
||||||
|
File = "quickjs.h", |
||||||
|
Kind = CInclude.IncludeKind.Angled |
||||||
|
}); |
||||||
|
|
||||||
|
foreach (var unit in TranslationUnits) |
||||||
|
{ |
||||||
|
WriteInclude(new CInclude() |
||||||
|
{ |
||||||
|
File = unit.FileName, |
||||||
|
Kind = CInclude.IncludeKind.Quoted |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
NewLine(); |
||||||
|
PopBlock(); |
||||||
|
|
||||||
|
VisitNamespace(TranslationUnit); |
||||||
|
} |
||||||
|
|
||||||
|
public override ParamMarshal GenerateFunctionParamMarshal(Parameter param, int paramIndex, |
||||||
|
Function function = null) |
||||||
|
{ |
||||||
|
var paramMarshal = new ParamMarshal { Name = param.Name, Param = param }; |
||||||
|
|
||||||
|
var argName = Generator.GeneratedIdentifier(param.Name); |
||||||
|
|
||||||
|
Parameter effectiveParam = param; |
||||||
|
var isRef = param.IsOut || param.IsInOut; |
||||||
|
var paramType = param.Type; |
||||||
|
|
||||||
|
var ctx = new MarshalContext(Context, CurrentIndentation) |
||||||
|
{ |
||||||
|
Parameter = effectiveParam, |
||||||
|
ParameterIndex = paramIndex, |
||||||
|
ArgName = argName, |
||||||
|
Function = function |
||||||
|
}; |
||||||
|
|
||||||
|
var marshal = new QuickJSMarshalManagedToNativePrinter(ctx); |
||||||
|
effectiveParam.Visit(marshal); |
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(marshal.Context.Before)) |
||||||
|
throw new Exception($"Cannot marshal argument of function '{function.QualifiedOriginalName}'"); |
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) |
||||||
|
Write(marshal.Context.Before); |
||||||
|
|
||||||
|
NewLine(); |
||||||
|
|
||||||
|
paramMarshal.Name = argName; |
||||||
|
return paramMarshal; |
||||||
|
} |
||||||
|
|
||||||
|
public override void GenerateFunctionCallReturnMarshal(Function function) |
||||||
|
{ |
||||||
|
var ctx = new MarshalContext(Context, CurrentIndentation) |
||||||
|
{ |
||||||
|
ArgName = Helpers.ReturnIdentifier, |
||||||
|
ReturnVarName = Helpers.ReturnIdentifier, |
||||||
|
ReturnType = function.ReturnType |
||||||
|
}; |
||||||
|
|
||||||
|
var marshal = new QuickJSMarshalNativeToManagedPrinter(ctx); |
||||||
|
function.ReturnType.Visit(marshal); |
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) |
||||||
|
Write(marshal.Context.Before); |
||||||
|
|
||||||
|
NewLine(); |
||||||
|
WriteLine($"return {marshal.Context.Return};"); |
||||||
|
} |
||||||
|
|
||||||
|
public override bool VisitFunctionDecl(Function function) |
||||||
|
{ |
||||||
|
Write("extern \"C\" "); |
||||||
|
WriteLine($"JSValue js_{function.Name}(JSContext* ctx, JSValueConst this_val,"); |
||||||
|
WriteLineIndent("int argc, JSValueConst* argv)"); |
||||||
|
WriteOpenBraceAndIndent(); |
||||||
|
|
||||||
|
GenerateFunctionCall(function); |
||||||
|
|
||||||
|
UnindentAndWriteCloseBrace(); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue