[c] Implement support for fields in reference and value types.
This commit is contained in:
Родитель
9483b1b262
Коммит
3af3f6e6a1
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -258,9 +258,7 @@ namespace MonoEmbeddinator4000.Generators
|
|||
continue;
|
||||
|
||||
var decl = VisitField(field);
|
||||
|
||||
// TODO: Ignore fields until we implement usage of FieldToPropertyPass
|
||||
//@class.Declarations.Add(decl);
|
||||
@class.Declarations.Add(decl);
|
||||
}
|
||||
|
||||
foreach (var @event in type.DeclaredEvents)
|
||||
|
@ -625,10 +623,12 @@ namespace MonoEmbeddinator4000.Generators
|
|||
|
||||
public Field VisitField(FieldInfo fieldInfo)
|
||||
{
|
||||
var field = new Field()
|
||||
var field = new Field
|
||||
{
|
||||
Name = UnmangleTypeName(fieldInfo.Name),
|
||||
QualifiedType = VisitType(fieldInfo.FieldType)
|
||||
Namespace = Visit(fieldInfo.DeclaringType.GetTypeInfo()) as Class,
|
||||
QualifiedType = VisitType(fieldInfo.FieldType),
|
||||
IsStatic = fieldInfo.IsStatic
|
||||
};
|
||||
|
||||
var accessMask = (fieldInfo.Attributes & FieldAttributes.FieldAccessMask);
|
||||
|
@ -644,17 +644,24 @@ namespace MonoEmbeddinator4000.Generators
|
|||
|
||||
public Property VisitProperty(PropertyInfo propertyInfo, Class @class)
|
||||
{
|
||||
var property = new Property()
|
||||
var property = new Property
|
||||
{
|
||||
Name = UnmangleTypeName(propertyInfo.Name),
|
||||
Namespace = Visit(propertyInfo.DeclaringType.GetTypeInfo()) as Class,
|
||||
QualifiedType = VisitType(propertyInfo.PropertyType),
|
||||
};
|
||||
|
||||
if (propertyInfo.GetMethod != null)
|
||||
{
|
||||
property.GetMethod = VisitMethod(propertyInfo.GetMethod, @class);
|
||||
property.GetMethod.Namespace = property.Namespace;
|
||||
}
|
||||
|
||||
if (propertyInfo.SetMethod != null)
|
||||
{
|
||||
property.SetMethod = VisitMethod(propertyInfo.SetMethod, @class);
|
||||
property.SetMethod.Namespace = property.Namespace;
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
|
|
@ -145,6 +145,20 @@ namespace MonoEmbeddinator4000.Generators
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool VisitProperty(Property property)
|
||||
{
|
||||
if (property.Field == null)
|
||||
return false;
|
||||
|
||||
var getter = property.GetMethod;
|
||||
VisitMethodDecl(getter);
|
||||
|
||||
var setter = property.SetMethod;
|
||||
VisitMethodDecl(setter);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -393,7 +393,7 @@ namespace MonoEmbeddinator4000.Generators
|
|||
var handle = CSources.GetMonoObjectField(Options, CSources.MonoObjectFieldUsage.Parameter,
|
||||
Context.ArgName, "_handle");
|
||||
|
||||
var @object = $"mono_gchandle_get_target({handle})";
|
||||
var @object = $"{Context.ArgName} ? mono_gchandle_get_target({handle}) : 0";
|
||||
|
||||
if (@class.IsValueType)
|
||||
@object = $"mono_object_unbox({@object})";
|
||||
|
|
|
@ -377,5 +377,130 @@ namespace MonoEmbeddinator4000.Generators
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void GenerateFieldLookup(Field field)
|
||||
{
|
||||
var fieldId = GeneratedIdentifier("field");
|
||||
WriteLine($"static MonoClassField *{fieldId} = 0;");
|
||||
|
||||
WriteLine($"if (!{fieldId})");
|
||||
WriteStartBraceIndent();
|
||||
|
||||
var @class = field.Namespace as Class;
|
||||
var classLookupId = GeneratedIdentifier($"lookup_class_{@class.QualifiedName.Replace('.', '_')}");
|
||||
WriteLine($"{classLookupId}();");
|
||||
|
||||
var fieldNameId = GeneratedIdentifier("field_name");
|
||||
WriteLine($"const char {fieldNameId}[] = \"{field.Name}\";");
|
||||
|
||||
var classId = $"class_{@class.QualifiedName}";
|
||||
WriteLine($"{fieldId} = mono_class_get_field_from_name({classId}, {fieldNameId});");
|
||||
|
||||
WriteCloseBraceIndent();
|
||||
}
|
||||
|
||||
public override bool VisitProperty(Property property)
|
||||
{
|
||||
if (property.Field == null)
|
||||
return false;
|
||||
|
||||
GenerateFieldGetter(property);
|
||||
NewLine();
|
||||
|
||||
GenerateFieldSetter(property);
|
||||
NewLine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GenerateFieldGetter(Property property)
|
||||
{
|
||||
var getter = property.GetMethod;
|
||||
|
||||
GenerateMethodSpecifier(getter, getter.Namespace as Class);
|
||||
NewLine();
|
||||
WriteStartBraceIndent();
|
||||
|
||||
var field = property.Field;
|
||||
GenerateFieldLookup(field);
|
||||
|
||||
var instanceId = field.IsStatic ? "0" : GeneratedIdentifier("instance");
|
||||
var resultId = GeneratedIdentifier("result");
|
||||
|
||||
if (!field.IsStatic)
|
||||
{
|
||||
var handle = GetMonoObjectField(Options, MonoObjectFieldUsage.Instance,
|
||||
FixMethodParametersPass.ObjectParameterId, "_handle");
|
||||
WriteLine($"MonoObject* {instanceId} = mono_gchandle_get_target({handle});");
|
||||
}
|
||||
|
||||
var fieldId = GeneratedIdentifier("field");
|
||||
var domainId = $"{GeneratedIdentifier("mono_context")}.domain";
|
||||
|
||||
WriteLine($"MonoObject* {resultId} = mono_field_get_value_object({domainId}, {fieldId}, {instanceId});");
|
||||
|
||||
var ctx = new MarshalContext(Context)
|
||||
{
|
||||
ArgName = resultId,
|
||||
ReturnVarName = resultId,
|
||||
ReturnType = property.QualifiedType
|
||||
};
|
||||
|
||||
var marshal = new CMarshalManagedToNative(EmbedOptions, ctx);
|
||||
property.QualifiedType.Visit(marshal);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
|
||||
Write(marshal.Context.SupportBefore);
|
||||
|
||||
WriteLine($"return {marshal.Context.Return.ToString()};");
|
||||
|
||||
WriteCloseBraceIndent();
|
||||
}
|
||||
|
||||
void GenerateFieldSetter(Property property)
|
||||
{
|
||||
var setter = property.SetMethod;
|
||||
var @class = property.Namespace as Class;
|
||||
|
||||
GenerateMethodSpecifier(setter, setter.Namespace as Class);
|
||||
NewLine();
|
||||
WriteStartBraceIndent();
|
||||
|
||||
var field = property.Field;
|
||||
var fieldId = GeneratedIdentifier("field");
|
||||
|
||||
GenerateFieldLookup(field);
|
||||
|
||||
var ctx = new MarshalContext(Context) { ArgName = "value" };
|
||||
var marshal = new CMarshalNativeToManaged(EmbedOptions, ctx);
|
||||
property.QualifiedType.Visit(marshal);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
|
||||
Write(marshal.Context.SupportBefore);
|
||||
|
||||
var valueId = GeneratedIdentifier("value");
|
||||
WriteLine($"void* {valueId} = {marshal.Context.Return.ToString()};");
|
||||
|
||||
if (field.IsStatic)
|
||||
{
|
||||
var vtableId = GeneratedIdentifier("vtable");
|
||||
var domainId = $"{GeneratedIdentifier("mono_context")}.domain";
|
||||
var classId = $"class_{@class.QualifiedName}";
|
||||
|
||||
WriteLine ($"MonoVTable* {vtableId} = mono_class_vtable({domainId}, {classId});");
|
||||
WriteLine ($"mono_field_static_set_value({vtableId}, {fieldId}, {valueId});");
|
||||
}
|
||||
else
|
||||
{
|
||||
var instanceId = GeneratedIdentifier("instance");
|
||||
var handle = GetMonoObjectField(Options, MonoObjectFieldUsage.Instance,
|
||||
FixMethodParametersPass.ObjectParameterId, "_handle");
|
||||
|
||||
WriteLine($"MonoObject* {instanceId} = mono_gchandle_get_target({handle});");
|
||||
WriteLine ($"mono_field_set_value({instanceId}, {fieldId}, {valueId});");
|
||||
}
|
||||
|
||||
WriteCloseBraceIndent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -427,6 +427,12 @@ namespace MonoEmbeddinator4000.Generators
|
|||
return true;
|
||||
}
|
||||
|
||||
public override bool VisitFieldDecl(Field field)
|
||||
{
|
||||
// Ignore fields since they're converted to getter/setter pais.
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string GetAccess(AccessSpecifier accessSpecifier)
|
||||
{
|
||||
switch (accessSpecifier)
|
||||
|
|
|
@ -4,68 +4,65 @@ using CppSharp.Passes;
|
|||
|
||||
namespace MonoEmbeddinator4000.Passes
|
||||
{
|
||||
public class FieldToGetterSetterPass : TranslationUnitPass
|
||||
public class FieldToGetterSetterPropertyPass : TranslationUnitPass
|
||||
{
|
||||
public override bool VisitFieldDecl(Field field)
|
||||
{
|
||||
if (!VisitDeclaration(field))
|
||||
return false;
|
||||
|
||||
var @class = field.Namespace as Class;
|
||||
if (@class == null)
|
||||
if (field.Access == AccessSpecifier.Private)
|
||||
return false;
|
||||
|
||||
if (field.Access == AccessSpecifier.Private)
|
||||
return true;
|
||||
|
||||
// Check if we already have a synthetized getter/setter.
|
||||
//var existing = @class.Methods.FirstOrDefault(
|
||||
// method => method.Parameters.SingleOrDefault(
|
||||
// (Parameter p) =>
|
||||
// {
|
||||
// Class paramClass;
|
||||
// if(!p.Type.TryGetClass(out paramClass))
|
||||
// return false;
|
||||
|
||||
// return paramClass == @class;
|
||||
// }));
|
||||
|
||||
//if (existing != null)
|
||||
// return false;
|
||||
if (field.IsImplicit)
|
||||
return false;
|
||||
|
||||
field.GenerationKind = GenerationKind.None;
|
||||
|
||||
var @class = field.Namespace as Class;
|
||||
|
||||
var getter = new Method
|
||||
{
|
||||
Name = string.Format("get{0}", field.Name),
|
||||
Name = $"get_{field.Name}",
|
||||
Namespace = @class,
|
||||
ReturnType = field.QualifiedType,
|
||||
Access = field.Access
|
||||
Access = field.Access,
|
||||
SynthKind = FunctionSynthKind.FieldAcessor,
|
||||
Field = field
|
||||
};
|
||||
|
||||
@class.Methods.Add(getter);
|
||||
|
||||
var setter = new Method
|
||||
{
|
||||
Name = string.Format("set{0}", field.Name),
|
||||
Name = $"set_{field.Name}",
|
||||
Namespace = @class,
|
||||
ReturnType = new QualifiedType(new BuiltinType(PrimitiveType.Void)),
|
||||
Access = field.Access,
|
||||
|
||||
SynthKind = FunctionSynthKind.FieldAcessor,
|
||||
Field = field
|
||||
};
|
||||
|
||||
var param = new Parameter
|
||||
{
|
||||
Name = "value",
|
||||
QualifiedType = field.QualifiedType
|
||||
QualifiedType = field.QualifiedType,
|
||||
};
|
||||
setter.Parameters.Add(param);
|
||||
|
||||
@class.Methods.Add(setter);
|
||||
var property = new Property
|
||||
{
|
||||
Name = field.Name,
|
||||
Namespace = field.Namespace,
|
||||
GetMethod = getter,
|
||||
SetMethod = setter,
|
||||
Field = field,
|
||||
QualifiedType = field.QualifiedType
|
||||
};
|
||||
|
||||
Diagnostics.Debug("Getter/setter created from field: {0}::{1}",
|
||||
@class.QualifiedOriginalName, field.Name);
|
||||
@class.Declarations.Add(property);
|
||||
|
||||
return false;
|
||||
Diagnostics.Debug($"Getter/setter property created from field {field.QualifiedName}");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,10 +66,25 @@ namespace MonoEmbeddinator4000.Passes
|
|||
if (method.IsConstructor)
|
||||
return false;
|
||||
|
||||
if (Options.GeneratorKind == GeneratorKind.C)
|
||||
var isStaticField = method.Field != null && method.Field.IsStatic;
|
||||
if (Options.GeneratorKind == GeneratorKind.C && !isStaticField)
|
||||
AddObjectParameterToMethod(method, @class);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool VisitProperty(Property property)
|
||||
{
|
||||
if (!VisitDeclaration(property))
|
||||
return false;
|
||||
|
||||
if (property.GetMethod != null)
|
||||
property.GetMethod.Visit(this);
|
||||
|
||||
if (property.SetMethod != null)
|
||||
property.SetMethod.Visit(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,7 +106,8 @@ namespace MonoEmbeddinator4000.Passes
|
|||
Name = CGenerator.ObjectInstanceId,
|
||||
QualifiedType = new QualifiedType(ptrType),
|
||||
Access = AccessSpecifier.Public,
|
||||
Namespace = @class
|
||||
Namespace = @class,
|
||||
IsImplicit = true
|
||||
};
|
||||
|
||||
@class.Fields.Add(field);
|
||||
|
|
|
@ -14,9 +14,7 @@ namespace MonoEmbeddinator4000.Passes
|
|||
if (!VisitDeclaration(property))
|
||||
return false;
|
||||
|
||||
var @class = property.Namespace as Class;
|
||||
if (@class == null)
|
||||
return false;
|
||||
return false;
|
||||
|
||||
property.GenerationKind = GenerationKind.None;
|
||||
|
||||
|
@ -29,6 +27,7 @@ namespace MonoEmbeddinator4000.Passes
|
|||
IsStatic = property.IsStatic
|
||||
};
|
||||
|
||||
var @class = property.Namespace as Class;
|
||||
@class.Methods.Add(getter);
|
||||
|
||||
var param = new Parameter
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 2670d47eb18953e889876fdca3e563dd0fc6240d
|
||||
Subproject commit bd86afa9a2ee16256ea552fe22bb44d9ee66477e
|
|
@ -238,6 +238,10 @@ TEST_CASE("Structs.C", "[C][Structs]") {
|
|||
|
||||
Structs_Point* p4 = Structs_Point_op_Subtraction(p3, p2);
|
||||
REQUIRE(Structs_Point_op_Equality(p4, p1) == true);
|
||||
|
||||
Structs_Point* z = Structs_Point_get_Zero();
|
||||
REQUIRE(Structs_Point_get_X(z) == 0.0f);
|
||||
REQUIRE(Structs_Point_get_Y(z) == 0.0f);
|
||||
}
|
||||
|
||||
TEST_CASE("Enums.C", "[C][Enums]") {
|
||||
|
@ -254,6 +258,72 @@ TEST_CASE("Enums.C", "[C][Enums]") {
|
|||
REQUIRE(s == Enums_ShortEnum_Min);
|
||||
}
|
||||
|
||||
TEST_CASE("FieldsInReference.C", "[C][Fields]") {
|
||||
REQUIRE(Fields_Class_get_MaxLong() == LONG_MAX);
|
||||
|
||||
REQUIRE(Fields_Class_get_Integer() == 0);
|
||||
Fields_Class_set_Integer(1);
|
||||
REQUIRE(Fields_Class_get_Integer() == 1);
|
||||
|
||||
Fields_Class* scratch = Fields_Class_get_Scratch();
|
||||
REQUIRE(Fields_Class_get_Boolean(scratch) == true);
|
||||
|
||||
scratch = Fields_Class_new(/*enabled=*/false);
|
||||
Fields_Class_set_Scratch(scratch);
|
||||
REQUIRE(Fields_Class_get_Boolean(scratch) == false);
|
||||
|
||||
Fields_Class* ref1 = Fields_Class_new(/*enabled=*/true);
|
||||
REQUIRE(Fields_Class_get_Boolean(ref1) == true);
|
||||
Fields_Class_set_Boolean(ref1, false);
|
||||
REQUIRE(Fields_Class_get_Boolean(ref1) == false);
|
||||
|
||||
Fields_Struct* struct1 = Fields_Class_get_Structure(ref1);
|
||||
REQUIRE(struct1 != NULL);
|
||||
REQUIRE(Fields_Struct_get_Boolean(struct1) == false);
|
||||
struct1 = Fields_Struct_new(/*enabled=*/true);
|
||||
REQUIRE(Fields_Struct_get_Boolean(struct1) == true);
|
||||
|
||||
Fields_Class* ref2 = Fields_Class_new(/*enabled=*/false);
|
||||
Fields_Struct* struct2 = Fields_Class_get_Structure(ref2);
|
||||
REQUIRE(struct2 != NULL);
|
||||
REQUIRE(Fields_Class_get_Boolean(ref2) == false);
|
||||
}
|
||||
|
||||
TEST_CASE("FieldsInValueType.C", "[C][Fields]") {
|
||||
REQUIRE(Fields_Struct_get_Integer() == 0);
|
||||
Fields_Struct_set_Integer(1);
|
||||
REQUIRE(Fields_Struct_get_Integer() == 1);
|
||||
|
||||
Fields_Struct* scratch = Fields_Struct_get_Scratch();
|
||||
REQUIRE(Fields_Struct_get_Boolean(scratch) == false);
|
||||
|
||||
scratch = Fields_Struct_new(/*enabled=*/true);
|
||||
Fields_Struct_set_Scratch(scratch);
|
||||
REQUIRE(Fields_Struct_get_Boolean(scratch) == true);
|
||||
|
||||
Fields_Struct* empty = Fields_Struct_get_Empty();
|
||||
REQUIRE(empty != NULL);
|
||||
REQUIRE(Fields_Struct_get_Class(empty) == NULL);
|
||||
|
||||
Fields_Struct* struct1 = Fields_Struct_new(/*enabled=*/true);
|
||||
REQUIRE(Fields_Struct_get_Boolean(struct1) == true);
|
||||
Fields_Struct_set_Boolean(struct1, false);
|
||||
REQUIRE(Fields_Struct_get_Boolean(struct1) == false);
|
||||
|
||||
Fields_Class* struct1_class = Fields_Struct_get_Class(struct1);
|
||||
REQUIRE(struct1_class != NULL);
|
||||
REQUIRE(Fields_Class_get_Boolean(struct1_class) == false);
|
||||
Fields_Struct_set_Class(struct1, NULL);
|
||||
REQUIRE(Fields_Struct_get_Class(struct1) == NULL);
|
||||
struct1_class = Fields_Class_new(/*enabled=*/true);
|
||||
REQUIRE(Fields_Class_get_Boolean(struct1_class) == true);
|
||||
|
||||
Fields_Struct* struct2 = Fields_Struct_new(/*enabled=*/false);
|
||||
Fields_Class* struct2_class = Fields_Struct_get_Class(struct2);
|
||||
REQUIRE(struct2_class != NULL);
|
||||
REQUIRE(Fields_Class_get_Boolean(struct2_class) == false);
|
||||
}
|
||||
|
||||
TEST_CASE("Interfaces.C", "[C][Interfaces]") {
|
||||
Interfaces_IMakeItUp* m = Interfaces_Supplier_Create();
|
||||
REQUIRE(Interfaces_IMakeItUp_get_Boolean(m) == true);
|
||||
|
|
Загрузка…
Ссылка в новой задаче