Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[methods aliases] Features for Function Type and load function as argument #250

Merged
merged 9 commits into from
Jun 29, 2024
1 change: 1 addition & 0 deletions compiler/compilation/CompilationTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ private bool ProcessFiles(IReadOnlyCollection<FileInfo> files, IReadOnlyCollecti
Target.AST.Select(x => (x.Key, x.Value))
.Pipe(x => Status.VeinStatus($"Linking [grey]'{x.Key.Name}'[/]..."))
.SelectMany(LinkClasses)
.Concat(aliasesQueue.SelectMany(RegenerateAliases))
.ToList()
.Pipe(LinkMetadata)
.Pipe(ShitcodePlug)
Expand Down
67 changes: 44 additions & 23 deletions compiler/compilation/parts/args.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ private VeinArgumentRef[] GenerateArgument(MethodDeclarationSyntax method, Docum
throw new SkipStatementException();
}

if (method.Modifiers.All(x => x.ModificatorKind != ModificatorKind.Static))
args.Add(new VeinArgumentRef(VeinArgumentRef.THIS_ARGUMENT, FetchType(method.OwnerClass.Identifier, doc)));
if (!method.IsMethodType) // check method has linked to class, otherwise it is an anonymous method type
{
if (method.Modifiers.All(x => x.ModificatorKind != ModificatorKind.Static))
args.Add(new VeinArgumentRef(VeinArgumentRef.THIS_ARGUMENT, FetchType(method.OwnerClass.Identifier, doc)));
}


if (method.Parameters.Count == 0)
return args.ToArray();
Expand All @@ -39,30 +43,47 @@ private IEnumerable<VeinArgumentRef> Convert(List<ParameterSyntax> args, MethodD
var constraints =
method.TypeParameterConstraints.FirstOrDefault(x => x.GenericIndex.Typeword.Equals(parameter.Type));

var classGeneric = method.OwnerClass.GenericTypes.FirstOrDefault(x => x.Typeword.Equals(parameter.Type));
var classGenericConstrains = method.OwnerClass.TypeParameterConstraints.FirstOrDefault(x => x.GenericIndex.Typeword.Equals(parameter.Type));

if (generic is not null && classGeneric is not null)
if (!method.IsMethodType)
{
Log.Defer.Error($"Detected conflict of declaration generic types, generic type '[red bold]{parameter.Type.Identifier}[/]' " +
$"is declared in the '[red bold]{method.Identifier}[/]' method and in the '[red bold]{method.OwnerClass.Identifier}[/]' class", generic, method.OwnerDocument);
throw new SkipStatementException();
}
var classGeneric = method.OwnerClass!.GenericTypes?.FirstOrDefault(x => x.Typeword.Equals(parameter.Type));
var classGenericConstrains = method.OwnerClass!.TypeParameterConstraints?.FirstOrDefault(x => x.GenericIndex.Typeword.Equals(parameter.Type));

if (generic is not null && constraints is not null)
yield return new VeinArgumentRef(name,
generic.Typeword.ToTypeArg([constraints.ToConstraint(selector)]));
else if (generic is not null)
yield return new VeinArgumentRef(name, generic.Typeword.ToTypeArg([]));
else if (classGeneric is not null && classGenericConstrains is not null)
yield return new VeinArgumentRef(name,
classGeneric.Typeword.ToTypeArg([classGenericConstrains.ToConstraint(selector)]));
else if (classGeneric is not null)
yield return new VeinArgumentRef(name, classGeneric.Typeword.ToTypeArg([]));
else if(parameter.Type.IsSelf)
yield return new VeinArgumentRef(name, FetchType(method.OwnerClass.Identifier, method.OwnerDocument));
if (generic is not null && classGeneric is not null)
{
Log.Defer.Error($"Detected conflict of declaration generic types, generic type '[red bold]{parameter.Type.Identifier}[/]' " +
$"is declared in the '[red bold]{method.Identifier}[/]' method and in the '[red bold]{method.OwnerClass!.Identifier}[/]' class", generic, method.OwnerDocument);
throw new SkipStatementException();
}
if (generic is not null && constraints is not null)
yield return new VeinArgumentRef(name,
generic.Typeword.ToTypeArg([constraints.ToConstraint(selector)]));
else if (generic is not null)
yield return new VeinArgumentRef(name, generic.Typeword.ToTypeArg([]));
else if (classGeneric is not null && classGenericConstrains is not null)
yield return new VeinArgumentRef(name,
classGeneric.Typeword.ToTypeArg([classGenericConstrains.ToConstraint(selector)]));
else if (classGeneric is not null)
yield return new VeinArgumentRef(name, classGeneric.Typeword.ToTypeArg([]));
else if (parameter.Type.IsSelf)
yield return new VeinArgumentRef(name, FetchType(method.OwnerClass.Identifier, method.OwnerDocument));
else
yield return new VeinArgumentRef(name, FetchType(parameter.Type, method.OwnerDocument));
}
else
yield return new VeinArgumentRef(name, FetchType(parameter.Type, method.OwnerDocument));
{
if (generic is not null && constraints is not null)
yield return new VeinArgumentRef(name,
generic.Typeword.ToTypeArg([constraints.ToConstraint(selector)]));
else if (generic is not null)
yield return new VeinArgumentRef(name, generic.Typeword.ToTypeArg([]));
else if (parameter.Type.IsSelf)
{
Log.Defer.Error($"self type is not supported in method type '[red bold]{parameter.Type.Identifier}[/]", parameter, method.OwnerDocument);
throw new SkipStatementException();
}
else
yield return new VeinArgumentRef(name, FetchType(parameter.Type, method.OwnerDocument));
}
}
}
}
103 changes: 99 additions & 4 deletions compiler/compilation/parts/classes.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
namespace vein.compilation;

using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using exceptions;
using extensions;
using ishtar;
using ishtar.emit;
using MoreLinq;
using runtime;
using syntax;
using vein.reflection;
using static runtime.MethodFlags;

public partial class CompilationTask
{
public void LinkMetadata((ClassBuilder @class, MemberDeclarationSyntax member) x)
{
if (x.member is not ClassDeclarationSyntax)
if (x.member is not ClassDeclarationSyntax clazz)
return;

var (@class, member) = (x.@class, x.member as ClassDeclarationSyntax);
var (@class, member) = (x.@class, xMember: clazz);
var doc = member.OwnerDocument;
@class.Flags = GenerateClassFlags(member);

Expand Down Expand Up @@ -146,6 +150,9 @@ public void GenerateLinksForAliases(DocumentDeclaration doc)
{

}

private Queue<(DocumentDeclaration doc, VeinCore types)> aliasesQueue { get; } = new();

public List<(ClassBuilder clazz, MemberDeclarationSyntax member)> LinkClasses(DocumentDeclaration doc, VeinCore types)
{
var classes = new List<(ClassBuilder clazz, MemberDeclarationSyntax member)>();
Expand All @@ -157,6 +164,9 @@ public void GenerateLinksForAliases(DocumentDeclaration doc)
Status.VeinStatus($"Regeneration class [grey]'{clazz.Identifier}'[/]");
clazz.OwnerDocument = doc;
var result = CompileClass(clazz, doc, types);

Debug.WriteLine($"compiled class '{result.FullName}'");

Context.Classes.Add(result.FullName, result);
classes.Add((result, clazz));
}
Expand All @@ -171,22 +181,107 @@ public void GenerateLinksForAliases(DocumentDeclaration doc)
else
Log.Defer.Warn($"[grey]Member[/] [yellow underline]'{member.GetType().Name}'[/] [grey]is not supported.[/]");
}

if (doc.Aliases.Any()) aliasesQueue.Enqueue((doc, types));

return classes;
}

private List<(ClassBuilder clazz, MemberDeclarationSyntax member)> RegenerateAliases(
(DocumentDeclaration doc, VeinCore types) data)
=> RegenerateAliases(data.doc, data.types);

private List<(ClassBuilder clazz, MemberDeclarationSyntax member)> RegenerateAliases(DocumentDeclaration doc, VeinCore types)
{
var classes = new List<(ClassBuilder clazz, MemberDeclarationSyntax member)>();
foreach (var alias in doc.Aliases)
{
if (alias.IsType)
{
var type = FetchType(alias.Type!.Typeword, doc);
Context.Module.alias_table.Add(new VeinAliasType($"{module.Name}%global::{doc.Name}/{alias.AliasName.ExpressionString}",
type));
type));

Status.VeinStatus($"Regeneration type alias [grey]'{type}'[/] -> [grey]'{alias.AliasName.ExpressionString}'[/]");

KnowClasses.Add(alias.AliasName, type);
}
else
Log.Defer.Warn($"Method [grey]Alias[/] [yellow underline]'{alias.AliasName.ExpressionString}'[/] [grey]is not supported.[/]");
{
var delegateClass = DefineDelegateClass(alias, doc, types);

Status.VeinStatus($"Regeneration method alias [grey]'{delegateClass.FullName}'[/]");

delegateClass.TypeCode = VeinTypeCode.TYPE_FUNCTION;
Context.Classes.Add(delegateClass.FullName, delegateClass);
classes.Add((delegateClass, null!));
}
}

return classes;
}

public ClassBuilder DefineDelegateClass(AliasSyntax alias, DocumentDeclaration doc, VeinCore types)
{
var aliasName = new QualityTypeName(module.Name, alias.AliasName.ExpressionString, $"global::{doc.Name}");
var multicastFnType = new QualityTypeName("std", "FunctionMulticast", $"global::std");

var args = GenerateArgument(alias.MethodDeclaration!, doc);

var retType = FetchType(alias.MethodDeclaration!.ReturnType, doc);
var sig = new VeinMethodSignature(retType, args);
Context.Module.alias_table.Add(new VeinAliasMethod(aliasName, sig));

var @base = module.FindType(multicastFnType, true);

var clazz = module.DefineClass(aliasName, @base)
.WithIncludes(doc.Includes);


clazz.TypeCode = VeinTypeCode.TYPE_FUNCTION;

var objType = VeinTypeCode.TYPE_OBJECT.AsClass(types);
var rawType = VeinTypeCode.TYPE_RAW.AsClass(types);

var ctorMethod = clazz.DefineMethod(VeinMethod.METHOD_NAME_CONSTRUCTOR, VeinTypeCode.TYPE_VOID.AsClass(types), [
new("fn", rawType),
new("scope", objType)
]);


var scope = clazz.DefineField("_scope", FieldFlags.Internal, objType);
var ptrRef = clazz.DefineField("_fn", FieldFlags.Internal, rawType);

var ctorGen = ctorMethod.GetGenerator();

ctorGen.Emit(OpCodes.LDARG_0);
ctorGen.Emit(OpCodes.STF, ptrRef);
ctorGen.Emit(OpCodes.LDARG_1);
ctorGen.Emit(OpCodes.STF, scope);
ctorGen.Emit(OpCodes.RET);

var method = clazz.DefineMethod("invoke", Internal | Special,
sig.ReturnType,sig.Arguments.Where(VeinMethodSignature.NotThis).ToArray());

var hasThis = sig.Arguments.All(VeinMethodSignature.NotThis);

var generator = method.GetGenerator();


if (hasThis)
generator.Emit(OpCodes.LDF, scope);
foreach (int i in ..method.Signature.ArgLength)
generator.Emit(OpCodes.LDARG_S, i); // TODO optimization for LDARG_X

generator.Emit(OpCodes.LDF, ptrRef);
generator.Emit(OpCodes.CALL_SP);
generator.Emit(OpCodes.RET);


KnowClasses.Add(alias.AliasName, clazz);
return clazz;
}

public ClassBuilder CompileClass(ClassDeclarationSyntax member, DocumentDeclaration doc, VeinCore types)
{
void _defineClass(ClassBuilder clz)
Expand Down
5 changes: 2 additions & 3 deletions compiler/compilation/parts/methods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,10 @@ private MethodFlags GenerateMethodFlags(MethodDeclarationSyntax method)

if (member.IsConstructor())
{
member.Identifier = new IdentifierExpression("ctor");

member.Identifier = new IdentifierExpression(VeinMethod.METHOD_NAME_CONSTRUCTOR);
if (args.Length == 0)
return (clazz.GetDefaultCtor() as MethodBuilder, member);
var ctor = clazz.DefineMethod("ctor", GenerateMethodFlags(member), clazz, args);
var ctor = clazz.DefineMethod(VeinMethod.METHOD_NAME_CONSTRUCTOR, GenerateMethodFlags(member), clazz, args);
CompileAspectFor(member, doc, ctor);
return (ctor, member);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/ast/syntax/VeinSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ from parameters in MethodParameters
from @as in Parse.Char(':').Token().Commented(this)
from type in TypeReference.Commented(this)
from constraints in GenericConstraintParser.Token().Optional()
from methodBody in BlockShortform<ReturnStatementSyntax>().Or(Block.Or(Parse.Char(';').Return(new EmptyBlockSyntax())))
from methodBody in BlockShortform<ReturnStatementSyntax>().Positioned()
.Or(Block.Or(Parse.Char(';').Return(new EmptyBlockSyntax())))
.Token().Positioned().Commented(this)
select new MethodDeclarationSyntax
{
Expand Down
9 changes: 5 additions & 4 deletions lib/ast/syntax/ast/MethodDeclarationSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ public class MethodDeclarationSyntax(MemberDeclarationSyntax? heading = null) :

public BlockSyntax? Body { get; set; }

public bool IsAbstract => Body == null;
public bool IsAbstract => Body is null or EmptyBlockSyntax;

public List<TypeParameterConstraintSyntax> TypeParameterConstraints { get; set; } = new();
public List<TypeExpression> GenericTypes { get; set; } = new();


public string GetQualityName()
=> $"{Identifier}({Parameters.Select(x => $"{(x.Type.IsSelf ? OwnerClass.Identifier : x.Type.Identifier)}").Join(",")})";
public string GetQualityName() => IsMethodType ? $"({Parameters.Select(x => $"{(x.Type.Identifier)}").Join(",")})" : $"{Identifier}({Parameters.Select(x => $"{(x.Type.IsSelf ? OwnerClass.Identifier : x.Type.Identifier)}").Join(",")})";

public override MemberDeclarationSyntax WithTypeAndName(ParameterSyntax typeAndName)
{
Expand All @@ -44,7 +43,9 @@ public override MemberDeclarationSyntax WithName(IdentifierExpression name)

public bool IsConstructor() => Identifier.ExpressionString.Equals("new");

public ClassDeclarationSyntax OwnerClass { get; set; }
public ClassDeclarationSyntax? OwnerClass { get; set; }

public bool IsMethodType => OwnerClass is null && IsAbstract && !Modifiers.Any();
Comment on lines +46 to +48
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider initializing OwnerClass in the constructor.

To ensure OwnerClass is always set correctly, consider initializing it in the constructor.

- public ClassDeclarationSyntax? OwnerClass { get; set; }
+ public ClassDeclarationSyntax? OwnerClass { get; set; }
+ public MethodDeclarationSyntax(MemberDeclarationSyntax? heading = null, ClassDeclarationSyntax? ownerClass = null) : base(heading)
+ {
+     OwnerClass = ownerClass;
+ }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public ClassDeclarationSyntax? OwnerClass { get; set; }
public bool IsMethodType => OwnerClass is null && IsAbstract && !Modifiers.Any();
public ClassDeclarationSyntax? OwnerClass { get; set; }
public MethodDeclarationSyntax(MemberDeclarationSyntax? heading = null, ClassDeclarationSyntax? ownerClass = null) : base(heading)
{
OwnerClass = ownerClass;
}
public bool IsMethodType => OwnerClass is null && IsAbstract && !Modifiers.Any();

}


Expand Down
28 changes: 13 additions & 15 deletions lib/ast/syntax/ast/ReturnStatementSyntax.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
namespace vein.syntax
{
using System.Collections.Generic;
using Sprache;
namespace vein.syntax;

public class ReturnStatementSyntax : StatementSyntax, IPositionAware<ReturnStatementSyntax>
{
public ReturnStatementSyntax(ExpressionSyntax e) => Expression = e;
public override SyntaxType Kind => SyntaxType.ReturnStatement;
using System.Collections.Generic;
using Sprache;

public override IEnumerable<BaseSyntax> ChildNodes => GetNodes(Expression);
public class ReturnStatementSyntax(ExpressionSyntax e) : StatementSyntax, IPositionAware<ReturnStatementSyntax>
{
public override SyntaxType Kind => SyntaxType.ReturnStatement;

public ExpressionSyntax Expression { get; set; }
public override IEnumerable<BaseSyntax> ChildNodes => GetNodes(Expression);

public new ReturnStatementSyntax SetPos(Position startPos, int length)
{
base.SetPos(startPos, length);
return this;
}
public ExpressionSyntax Expression { get; set; } = e;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize properties in the constructor.

It's better to initialize the Expression property in the constructor to ensure it's always set correctly.

- public ExpressionSyntax Expression { get; set; } = e;
+ public ExpressionSyntax Expression { get; set; }
+ public ReturnStatementSyntax(ExpressionSyntax e)
+ {
+     Expression = e;
+ }

Committable suggestion was skipped due to low confidence.

public new ReturnStatementSyntax SetPos(Position startPos, int length)
{
base.SetPos(startPos, length);
return this;
}
Comment on lines +14 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using the new keyword to hide inherited members.

Using the new keyword to hide inherited members can lead to confusion. Consider renaming the method or using explicit interface implementation.

- public new ReturnStatementSyntax SetPos(Position startPos, int length)
+ public ReturnStatementSyntax SetPosition(Position startPos, int length)

Committable suggestion was skipped due to low confidence.

}
4 changes: 3 additions & 1 deletion metadata/db_opcodes.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,7 @@
"SEH.FINALLY": 110,
"SEH.FILTER": 111,
"SEH.ENTER": 112,
"CAST": 113
"CAST": 113,
"CALL_SP": 114,
"LDFN": 115
}
8 changes: 8 additions & 0 deletions metadata/opcodes.def.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ public enum OpCodeValue : ushort
/// </summary>
CALL = 0x32,
/// <summary>
/// Call operation (load pointer from stack).
/// </summary>
CALL_SP = 0x72,
/// <summary>
/// Load function pointer into stack.
/// </summary>
LDFN = 0x73,
/// <summary>
/// Load NULL into stack.
/// </summary>
LDNULL = 0x33,
Expand Down
Loading
Loading