Skip to content

Commit

Permalink
Merge pull request #250 from vein-lang/feature/generic-and-type-alias…
Browse files Browse the repository at this point in the history
…es-imrovements

[methods aliases] Features for Function Type and load function as argument
  • Loading branch information
0xF6 authored Jun 29, 2024
2 parents 8f089a6 + 594cd24 commit 8aa6748
Show file tree
Hide file tree
Showing 25 changed files with 517 additions and 165 deletions.
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();
}


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;

public new ReturnStatementSyntax SetPos(Position startPos, int length)
{
base.SetPos(startPos, length);
return this;
}
}
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

0 comments on commit 8aa6748

Please sign in to comment.