Skip to content

Commit

Permalink
Now only crashes
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrawehr committed Apr 14, 2024
1 parent d56ef6a commit 7af8aa8
Show file tree
Hide file tree
Showing 11 changed files with 317 additions and 7 deletions.
2 changes: 2 additions & 0 deletions tools/ArduinoCsCompiler/ArduinoCsCompiler.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
<ItemGroup>
<Compile Include="NanoGenerator\ClassWrapper.cs" />
<Compile Include="NanoGenerator\FieldWrapper.cs" />
<Compile Include="NanoGenerator\MethodWrapper.cs" />
<Compile Include="NanoGenerator\ParameterWrapper.cs" />
</ItemGroup>

</Project>
17 changes: 14 additions & 3 deletions tools/ArduinoCsCompiler/ArduinoMethodDeclaration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Iot.Device.Arduino;
Expand All @@ -27,7 +28,8 @@ public ArduinoMethodDeclaration(int token, EquatableMethod methodBase, ArduinoMe
NativeMethod = 0;
Code = code;
ArgumentCount = methodBase.GetParameters().Length;
if (methodBase.CallingConvention.HasFlag(CallingConventions.HasThis))
HasThis = methodBase.CallingConvention.HasFlag(CallingConventions.HasThis);
if (HasThis)
{
ArgumentCount += 1;
}
Expand All @@ -48,7 +50,7 @@ public ArduinoMethodDeclaration(int token, EquatableMethod methodBase, ArduinoMe
Code = code;
Flags = extraFlags;
Token = token;

HasThis = methodBase.CallingConvention.HasFlag(CallingConventions.HasThis);
var attribs = methodBase.GetCustomAttributes(typeof(ArduinoImplementationAttribute)).Cast<ArduinoImplementationAttribute>().ToList();

if (methodBase.IsAbstract)
Expand Down Expand Up @@ -81,7 +83,7 @@ public ArduinoMethodDeclaration(int token, EquatableMethod methodBase, ArduinoMe
}

ArgumentCount = methodBase.GetParameters().Length;
if (methodBase.CallingConvention.HasFlag(CallingConventions.HasThis))
if (HasThis)
{
ArgumentCount += 1;
}
Expand Down Expand Up @@ -126,8 +128,12 @@ public ArduinoMethodDeclaration(int token, EquatableMethod methodBase, ArduinoMe
Name = $"{MethodBase.MethodSignature()} (Token 0x{Token:X})";
}

/// <summary>
/// This is only used for declaring native members
/// </summary>
public ArduinoMethodDeclaration(int token, EquatableMethod methodBase, ArduinoMethodDeclaration? requestedBy, MethodFlags flags, int nativeMethod)
{
HasThis = methodBase.CallingConvention.HasFlag(CallingConventions.HasThis);
Index = -1;
Token = token;
MethodBase = methodBase;
Expand Down Expand Up @@ -168,6 +174,11 @@ public ArduinoMethodDeclaration(int token, EquatableMethod methodBase, ArduinoMe
Name = $"{MethodBase.MethodSignature()} (Special Method, Token 0x{Token:X})";
}

public bool HasThis
{
get;
}

public bool HasBody
{
get;
Expand Down
1 change: 1 addition & 0 deletions tools/ArduinoCsCompiler/ClassMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public ClassMember(string name, VariableKind variableType, int token, int sizeOf
BaseTokens = null;
SizeOfField = sizeOfField;
Name = name;
FieldName = name;
}

public ClassMember(FieldInfo field, VariableKind variableType, int token, int sizeOfField, int offset, int staticFieldSize)
Expand Down
40 changes: 38 additions & 2 deletions tools/ArduinoCsCompiler/ExecutionSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,37 @@ internal bool AddClass(ClassDeclaration type)
return true;
}

/// <summary>
/// Gets the argument type list of a method. Only works after the class list is generated
/// </summary>
internal List<ClassDeclaration> GetArgumentTypes(EquatableMethod methodInfo)
{
List<ClassDeclaration> ret = new List<ClassDeclaration>();
var param1 = methodInfo.Method.GetParameters();
for (int i = 0; i < param1.Length; i++)
{
var p1 = param1[i].ParameterType;
ClassDeclaration cls;
if (p1.IsArray)
{
cls = GetClass(p1.GetElementType()) ?? throw new InvalidOperationException($"Could not find original type of array {p1}");
}
else if (p1.IsByRef)
{
var elem = p1.GetElementType();
cls = GetClass(elem) ?? throw new InvalidOperationException($"Could not find real type of ref argument {p1}");
}
else
{
cls = GetClass(p1) ?? throw new InvalidOperationException($"Could not find type of parameter {param1[i]}");
}

ret.Add(cls);
}

return ret;
}

internal bool IsSuppressed(Type t)
{
return _classesToSuppress.Contains(t);
Expand Down Expand Up @@ -1409,9 +1440,14 @@ internal String GetString(int token)
return entry.StringData;
}

internal ArduinoMethodDeclaration GetMethod(EquatableMethod methodInfo)
internal ArduinoMethodDeclaration? GetMethod(EquatableMethod methodInfo, bool throwOnError = true)
{
return _methods.First(x => EquatableMethod.AreMethodsIdentical(x.MethodBase, methodInfo));
if (throwOnError)
{
return _methods.First(x => EquatableMethod.AreMethodsIdentical(x.MethodBase, methodInfo));
}

return _methods.FirstOrDefault(x => EquatableMethod.AreMethodsIdentical(x.MethodBase, methodInfo));
}

private static int Xor(IEnumerable<int> inputs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"BlinkingLed": {
"commandName": "Project",
"commandLineArgs": "compile --run ..\\..\\..\\..\\samples\\BlinkingLed\\bin\\$(Configuration)\\net6.0\\BlinkingLed.exe --network localhost --mapfile ..\\..\\..\\..\\samples\\BlinkingLed\\bin\\$(Configuration)\\net6.0\\BlinkingLed-tokenmap.txt --compileonly"
"commandLineArgs": "compile --run ..\\..\\..\\..\\samples\\BlinkingLed\\bin\\$(Configuration)\\net6.0\\BlinkingLed.exe --network localhost --mapfile ..\\..\\..\\..\\samples\\BlinkingLedNano\\BlinkingLed-tokenmap.txt --compileonly"
},
"Help": {
"commandName": "Project",
Expand Down
32 changes: 32 additions & 0 deletions tools/ArduinoCsCompiler/IlWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.TypeSystem;
using Microsoft.CodeAnalysis;
using SyntaxTree = ICSharpCode.Decompiler.CSharp.Syntax.SyntaxTree;

namespace ArduinoCsCompiler
{
Expand Down Expand Up @@ -73,6 +75,21 @@ public static void WriteMethod(TextWriter w, ArduinoMethodDeclaration code, Exec
w.WriteLine("}");
}

public static bool ClassToIgnoreAsParent(ClassDeclaration t)
{
if (t.TheType == typeof(object))
{
return true;
}

if (t.TheType == typeof(ValueType))
{
return true;
}

return false;
}

public void Write(string sourceFile, string outFile)
{
var settings = new DecompilerSettings()
Expand All @@ -87,6 +104,12 @@ public void Write(string sourceFile, string outFile)

foreach (var cls in _executionSet.Classes)
{
// Don't write the definition of System.Object.
if (cls.NewToken == (int)KnownTypeTokens.Object)
{
continue;
}

var typeSystemAstBuilder = new TypeSystemAstBuilder();
var wrapped = new ClassWrapper(cls, _executionSet);
EntityDeclaration decl = typeSystemAstBuilder.ConvertEntity(wrapped);
Expand All @@ -98,9 +121,18 @@ public void Write(string sourceFile, string outFile)
if (member.Field != null)
{
var fieldWrapped = new FieldWrapper(cls, member, _executionSet);
decl.AddChild(new Comment($"<summary>{member.Name}</summary>", CommentType.Documentation), Roles.Comment);
EntityDeclaration fld = typeSystemAstBuilder.ConvertEntity(fieldWrapped);
decl.AddChild(fld, Roles.TypeMemberRole);
}

if (member.Method != null)
{
var methodWrapped = new MethodWrapper(cls, member, _executionSet);
decl.AddChild(new Comment($"<summary>{member.Name}</summary>", CommentType.Documentation), Roles.Comment);
EntityDeclaration method = typeSystemAstBuilder.ConvertEntity(methodWrapped);
decl.AddChild(method, Roles.TypeMemberRole);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions tools/ArduinoCsCompiler/MicroCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System.Runtime.Serialization;
using System.Threading;
using ArduinoCsCompiler.Runtime;
using ICSharpCode.Decompiler.IL;
using Iot.Device.Arduino;
using Iot.Device.Common;
using Microsoft.CodeAnalysis;
Expand Down
2 changes: 1 addition & 1 deletion tools/ArduinoCsCompiler/NanoGenerator/ClassWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ public IEnumerable<IType> DirectBaseTypes
{
List<IType> baseTypes = new List<IType>();
var myBase = _executionSet.Classes.FirstOrDefault(x => x.TheType == _cls.TheType.BaseType);
if (myBase != null && myBase.TheType != typeof(object))
if (myBase != null && !IlWriter.ClassToIgnoreAsParent(myBase))
{
baseTypes.Add(new ClassWrapper(myBase, _executionSet));
}
Expand Down
1 change: 1 addition & 0 deletions tools/ArduinoCsCompiler/NanoGenerator/FieldWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public string Name
return $"Field_{_memberField.Token:X8}";
}
}

public bool IsReadOnly => _memberField.Field.IsInitOnly;
public bool ReturnTypeIsRefReadOnly { get; }
public bool IsVolatile { get; }
Expand Down
168 changes: 168 additions & 0 deletions tools/ArduinoCsCompiler/NanoGenerator/MethodWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.TypeSystem;

namespace ArduinoCsCompiler.NanoGenerator
{
internal class MethodWrapper : IEntity, IMethod
{
private readonly ClassMember _memberField;
private readonly ExecutionSet _executionSet;
private readonly ArduinoMethodDeclaration? _arduinoMethod;
private string _name;
private IType _declaringType;

public MethodWrapper(ClassDeclaration owner, ClassMember memberField, ExecutionSet executionSet)
{
_memberField = memberField;
_executionSet = executionSet;
_declaringType = new ClassWrapper(owner, executionSet);
_name = $"Method_{memberField.Token:X8}";
_arduinoMethod = executionSet.GetMethod(memberField.Method, false);
}

public SymbolKind SymbolKind
{
get
{
if (IsConstructor)
{
return SymbolKind.Constructor;
}

if (_memberField.Method is MethodInfo mf)
{
if (mf.IsSpecialName)
{
if (mf.Name.StartsWith("get_") || mf.Name.StartsWith("set_"))
{
return SymbolKind.Accessor;
}

// TODO: Operators, Destructors, etc.
}

return SymbolKind.Method;
}

throw new NotSupportedException("Invalid type detected");
}
}

string IEntity.Name => _name;

public ITypeDefinition? DeclaringTypeDefinition { get; }

IType IMember.DeclaringType => _declaringType;

public IEnumerable<IMember> ExplicitlyImplementedInterfaceMembers { get; }
public bool IsExplicitInterfaceImplementation { get; }

public bool IsVirtual
{
get => _memberField.Method.IsVirtual;
}

public bool IsOverride => false;
public bool IsOverridable => IsVirtual;
public TypeParameterSubstitution Substitution { get; }
public IEnumerable<IAttribute> GetReturnTypeAttributes()
{
throw new NotImplementedException();
}

public IMethod Specialize(TypeParameterSubstitution substitution)
{
throw new NotImplementedException();
}

public bool ReturnTypeIsRefReadOnly { get; }
public bool IsInitOnly { get; }
public bool ThisIsRefReadOnly { get; }
public IReadOnlyList<ITypeParameter> TypeParameters { get; }
public IReadOnlyList<IType> TypeArguments { get; }
public bool IsExtensionMethod { get; }
public bool IsLocalFunction { get; }
public bool IsConstructor => _memberField.Method.IsConstructor;
public bool IsDestructor { get; }
public bool IsOperator { get; }
public bool HasBody => _arduinoMethod != null && _arduinoMethod.HasBody;
public bool IsAccessor { get; }
public IMember? AccessorOwner { get; }
public MethodSemanticsAttributes AccessorKind { get; }
public IMethod? ReducedFrom { get; }

IMember IMember.Specialize(TypeParameterSubstitution substitution)
{
return Specialize(substitution);
}

public bool Equals(IMember? obj, TypeVisitor typeNormalization)
{
throw new NotImplementedException();
}

public IMember MemberDefinition { get; }
public IType ReturnType { get; }

IType? IEntity.DeclaringType => _declaringType;

public IModule? ParentModule { get; }
public Accessibility Accessibility { get; }
public bool IsStatic { get; }
public bool IsAbstract { get; }
public bool IsSealed { get; }
public string FullName { get; }
public IEnumerable<IAttribute> GetAttributes()
{
throw new NotImplementedException();
}

public bool HasAttribute(KnownAttribute attribute)
{
throw new NotImplementedException();
}

public IAttribute? GetAttribute(KnownAttribute attribute)
{
throw new NotImplementedException();
}

public EntityHandle MetadataToken { get; }

string INamedElement.Name => _name;

public string ReflectionName { get; }
public string Namespace => string.Empty;

string ISymbol.Name => _name;

public ICompilation Compilation { get; }

public IReadOnlyList<IParameter> Parameters
{
get
{
List<IParameter> ret = new List<IParameter>();
if (_arduinoMethod != null) // this can be null on non-existing methods (but why do we try to syntesize those?)
{
var input = _executionSet.GetArgumentTypes(_arduinoMethod.MethodBase);
for (int i = 0; i < input.Count; i++)
{
ret.Add(new ParameterWrapper(input[i], i, _executionSet));
}
}

return ret;
}
}
}
}
Loading

0 comments on commit 7af8aa8

Please sign in to comment.