diff --git a/compiler/compilation/CompilationTask.cs b/compiler/compilation/CompilationTask.cs index 1117cd6f..0afed5c7 100644 --- a/compiler/compilation/CompilationTask.cs +++ b/compiler/compilation/CompilationTask.cs @@ -222,6 +222,7 @@ private bool ProcessFiles(IReadOnlyCollection 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) diff --git a/compiler/compilation/parts/args.cs b/compiler/compilation/parts/args.cs index df2b4f39..8183ebd9 100644 --- a/compiler/compilation/parts/args.cs +++ b/compiler/compilation/parts/args.cs @@ -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(); @@ -39,30 +43,47 @@ private IEnumerable Convert(List 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)); + } } } } diff --git a/compiler/compilation/parts/classes.cs b/compiler/compilation/parts/classes.cs index d1dcdadc..d12c2331 100644 --- a/compiler/compilation/parts/classes.cs +++ b/compiler/compilation/parts/classes.cs @@ -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); @@ -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)>(); @@ -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)); } @@ -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) diff --git a/compiler/compilation/parts/methods.cs b/compiler/compilation/parts/methods.cs index a9080645..71bb661f 100644 --- a/compiler/compilation/parts/methods.cs +++ b/compiler/compilation/parts/methods.cs @@ -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); } diff --git a/lib/ast/syntax/VeinSyntax.cs b/lib/ast/syntax/VeinSyntax.cs index 60231748..bc297362 100644 --- a/lib/ast/syntax/VeinSyntax.cs +++ b/lib/ast/syntax/VeinSyntax.cs @@ -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().Or(Block.Or(Parse.Char(';').Return(new EmptyBlockSyntax()))) + from methodBody in BlockShortform().Positioned() + .Or(Block.Or(Parse.Char(';').Return(new EmptyBlockSyntax()))) .Token().Positioned().Commented(this) select new MethodDeclarationSyntax { diff --git a/lib/ast/syntax/ast/MethodDeclarationSyntax.cs b/lib/ast/syntax/ast/MethodDeclarationSyntax.cs index d10884a3..4d912bb9 100644 --- a/lib/ast/syntax/ast/MethodDeclarationSyntax.cs +++ b/lib/ast/syntax/ast/MethodDeclarationSyntax.cs @@ -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 TypeParameterConstraints { get; set; } = new(); public List 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) { @@ -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(); } diff --git a/lib/ast/syntax/ast/ReturnStatementSyntax.cs b/lib/ast/syntax/ast/ReturnStatementSyntax.cs index 3897c9dd..5fb2713a 100644 --- a/lib/ast/syntax/ast/ReturnStatementSyntax.cs +++ b/lib/ast/syntax/ast/ReturnStatementSyntax.cs @@ -1,21 +1,19 @@ -namespace vein.syntax -{ - using System.Collections.Generic; - using Sprache; +namespace vein.syntax; - public class ReturnStatementSyntax : StatementSyntax, IPositionAware - { - public ReturnStatementSyntax(ExpressionSyntax e) => Expression = e; - public override SyntaxType Kind => SyntaxType.ReturnStatement; +using System.Collections.Generic; +using Sprache; - public override IEnumerable ChildNodes => GetNodes(Expression); +public class ReturnStatementSyntax(ExpressionSyntax e) : StatementSyntax, IPositionAware +{ + public override SyntaxType Kind => SyntaxType.ReturnStatement; - public ExpressionSyntax Expression { get; set; } + public override IEnumerable 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; } } diff --git a/metadata/db_opcodes.json b/metadata/db_opcodes.json index 10111e41..3e2ea356 100644 --- a/metadata/db_opcodes.json +++ b/metadata/db_opcodes.json @@ -112,5 +112,7 @@ "SEH.FINALLY": 110, "SEH.FILTER": 111, "SEH.ENTER": 112, - "CAST": 113 + "CAST": 113, + "CALL_SP": 114, + "LDFN": 115 } \ No newline at end of file diff --git a/metadata/opcodes.def.cs b/metadata/opcodes.def.cs index ccad1aab..700c0c28 100644 --- a/metadata/opcodes.def.cs +++ b/metadata/opcodes.def.cs @@ -208,6 +208,14 @@ public enum OpCodeValue : ushort /// CALL = 0x32, /// + /// Call operation (load pointer from stack). + /// + CALL_SP = 0x72, + /// + /// Load function pointer into stack. + /// + LDFN = 0x73, + /// /// Load NULL into stack. /// LDNULL = 0x33, diff --git a/metadata/opcodes.list.def.cs b/metadata/opcodes.list.def.cs index d52da017..8506dda2 100644 --- a/metadata/opcodes.list.def.cs +++ b/metadata/opcodes.list.def.cs @@ -6,7 +6,7 @@ namespace ishtar using global::System.Collections.Generic; public static class OpCodes { - internal static int SetVersion = 18; + internal static int SetVersion = 20; /// /// Nope operation. /// size: 0 @@ -365,6 +365,20 @@ public static class OpCodes /// public static readonly OpCode CALL = new (0x32, 0x0200001F); /// + /// Call operation (load pointer from stack). + /// size: 0 + /// flow: 0 + /// chain: 0 + /// + public static readonly OpCode CALL_SP = new (0x72, 0x0000001F); + /// + /// Load function pointer into stack. + /// size: 8 + /// flow: 0 + /// chain: 0 + /// + public static readonly OpCode LDFN = new (0x73, 0x0200001F); + /// /// Load NULL into stack. /// size: 0 /// flow: 0 @@ -859,6 +873,8 @@ public static class OpCodes {OpCodeValue.RESERVED_2, RESERVED_2}, {OpCodeValue.RET, RET}, {OpCodeValue.CALL, CALL}, + {OpCodeValue.CALL_SP, CALL_SP}, + {OpCodeValue.LDFN, LDFN}, {OpCodeValue.LDNULL, LDNULL}, {OpCodeValue.LDF, LDF}, {OpCodeValue.LDSF, LDSF}, diff --git a/metadata/opcodes.yaml b/metadata/opcodes.yaml index 2dd4d4be..d2050664 100644 --- a/metadata/opcodes.yaml +++ b/metadata/opcodes.yaml @@ -56,6 +56,11 @@ - CALL: description: Call operation. override-size: 8 +- CALL_SP: + description: Call operation (load pointer from stack). +- LDFN: + description: Load function pointer into stack. + override-size: 8 - LDNULL: description: Load NULL into stack. - LDF: diff --git a/metadata/version b/metadata/version index 25bf17fc..2edeafb0 100644 --- a/metadata/version +++ b/metadata/version @@ -1 +1 @@ -18 \ No newline at end of file +20 \ No newline at end of file diff --git a/runtime/common/reflection/VeinClass.cs b/runtime/common/reflection/VeinClass.cs index 5162eddb..f7c0fe99 100644 --- a/runtime/common/reflection/VeinClass.cs +++ b/runtime/common/reflection/VeinClass.cs @@ -70,8 +70,8 @@ internal VeinClass(QualityTypeName name, VeinClass[] parents, VeinModule module) public bool IsValueType => IsPrimitive || this.Walk(x => x.Name == "ValueType"); public bool IsInterface => Flags.HasFlag(ClassFlags.Interface); - public virtual VeinMethod GetDefaultDtor() => GetOrCreateTor("dtor"); - public virtual VeinMethod GetDefaultCtor() => GetOrCreateTor("ctor"); + public virtual VeinMethod GetDefaultDtor() => GetOrCreateTor(VeinMethod.METHOD_NAME_DECONSTRUCTOR); + public virtual VeinMethod GetDefaultCtor() => GetOrCreateTor(VeinMethod.METHOD_NAME_CONSTRUCTOR); public virtual VeinMethod GetStaticCtor() => GetOrCreateTor("type_ctor", true); @@ -99,11 +99,31 @@ public VeinMethod FindMethod(string name, IEnumerable user_type if (!argsHas && !args.Any(z => z.IsGeneric) && !userTypes.Any(z => z.IsGeneric)) argsHas = CheckInheritance(userTypes.Select(z => z.Class).ToArray(), args.Select(z => z.Class).ToArray()); - + return argsHas; }); + public List FindAnyMethods(string name) => + Methods.Concat(Parents.SelectMany(x => x.Methods)) + .Where(x => { + var nameHas = x.RawName.Equals(name); + + if (!nameHas) + return false; + return true; + }).ToList(); + private bool CheckCompatibilityFunctionClass(VeinClass userArg, VeinClass methodArg) + { + var userInvoke = userArg.FindMethod("invoke"); + var methodInvoke = methodArg.FindMethod("invoke"); + + if (userInvoke is null || methodInvoke is null) + return false; + + return userInvoke.Signature.HasCompatibility(methodInvoke.Signature); + } + private bool CheckCompatibility(List userArgs, List methodArgs) { if (userArgs.Count != methodArgs.Count) return false; @@ -122,7 +142,10 @@ private bool CheckCompatibility(List userArgs, List userArgs, List methodArgs) - { - if (userArgs.Count != methodArgs.Count) return false; - - var genericMap = new Dictionary(); - - for (int i = 0; i < userArgs.Count; i++) - { - var userType = userArgs[i]; - var methodType = methodArgs[i]; - - if (methodType.IsGeneric) - { - var genericName = methodType.TypeArg.Name; - if (userType.IsGeneric) - { - if (!methodType.TypeArg.Name.Equals(userType.TypeArg.Name)) - return false; - } - else - { - if (genericMap.TryGetValue(genericName, out var value)) - { - if (!value.FullName.Equals(userType.Class.FullName)) - return false; - } - else - genericMap[genericName] = userType.Class; - } - } - else - { - if (userType.IsGeneric) - return false; - if (!methodType.Class.FullName.Equals(userType.Class.FullName)) - return false; - } - } - return true; - } - - - private bool CheckCompatibilityV2(List userArgs, List methodArgs) - { - if (userArgs.Count != methodArgs.Count) return false; - - Dictionary genericMap = new(); - - for (int i = 0; i < userArgs.Count; i++) - { - var userType = userArgs[i]; - var methodType = methodArgs[i]; - - if (methodType.IsGeneric) - { - var genericName = methodType.TypeArg.Name; - if (genericMap.TryGetValue(genericName, out var value)) - { - if (!value.FullName.Equals(userType.Class.FullName)) - return false; - } - else - genericMap[genericName] = userType.Class; - } - else - { - if (!methodType.Class.FullName.Equals(userType.Class.FullName)) - return false; - } - } - return true; - } - - private bool CheckCompatibilityV1(List userArgs, List methodArgs) - { - if (userArgs.Count != methodArgs.Count) return false; - - Dictionary genericMap = new(); - - for (int i = 0; i < userArgs.Count; i++) - { - var userType = userArgs[i]; - var methodType = methodArgs[i]; - - if (methodType.IsGeneric) - { - var genericName = methodType.TypeArg.Name; - if (genericMap.TryAdd(genericName, userType)) continue; - if (!genericMap[genericName].FullName.Equals(userType.FullName)) - return false; - } - else if (!methodType.Class.FullName.Equals(userType.FullName)) - return false; - } - return true; - } - private bool CheckInheritance(VeinClass[] current, VeinClass[] target) { if (current.Length != target.Length) diff --git a/runtime/common/reflection/VeinMethod.cs b/runtime/common/reflection/VeinMethod.cs index 325f6680..b5197864 100644 --- a/runtime/common/reflection/VeinMethod.cs +++ b/runtime/common/reflection/VeinMethod.cs @@ -55,10 +55,36 @@ public record VeinMethodSignature( public override string ToString() => $"({Arguments.Where(NotThis).Select(x => $"{x.ToTemplateString()}").Join(',')}) -> {ReturnType.ToTemplateString()}"; - private bool NotThis(VeinArgumentRef @ref) => !@ref.Name.Equals(VeinArgumentRef.THIS_ARGUMENT); + public static bool NotThis(VeinArgumentRef @ref) => !@ref.Name.Equals(VeinArgumentRef.THIS_ARGUMENT); public bool IsGeneric => Arguments.Any(x => x.IsGeneric); + public bool HasCompatibility(VeinMethodSignature otherSig) + { + if (ArgLength != otherSig.ArgLength) + return false; + + var argumentsCompatibility = true; + for (int i = 0; i < Arguments.Count; i++) + { + var a1 = Arguments[i]; + var a2 = otherSig.Arguments[i]; + + if (a1.IsGeneric != a2.IsGeneric) + { + argumentsCompatibility = false; + break; + } + if (a1.IsGeneric) + continue; + if (a1.Type.FullName != a2.Type.FullName) + argumentsCompatibility = false; + } + + return argumentsCompatibility; + } + + public string ToTemplateString() => ToString(); } @@ -70,6 +96,9 @@ public class VeinMethod : VeinMember, IAspectable public Dictionary Locals { get; } = new(); public List Aspects { get; } = new(); + public const string METHOD_NAME_CONSTRUCTOR = "ctor"; + public const string METHOD_NAME_DECONSTRUCTOR = "dtor"; + public void Temp_ReplaceReturnType(VeinClass clazz) => Signature = Signature with { ReturnType = clazz }; @@ -104,9 +133,9 @@ public static string GetFullName(string name, VeinComplexType returnType, IEnume public bool IsAbstract => Flags.HasFlag(MethodFlags.Abstract); public bool IsVirtual => Flags.HasFlag(MethodFlags.Virtual); public bool IsOverride => !Flags.HasFlag(MethodFlags.Abstract) && Flags.HasFlag(MethodFlags.Override); - public bool IsConstructor => RawName.Equals("ctor"); + public bool IsConstructor => RawName.Equals(METHOD_NAME_CONSTRUCTOR); public bool IsTypeConstructor => RawName.Equals("type_ctor"); - public bool IsDeconstructor => RawName.Equals("dtor"); + public bool IsDeconstructor => RawName.Equals(METHOD_NAME_DECONSTRUCTOR); public override bool IsSpecial => Flags.HasFlag(MethodFlags.Special); public sealed override string Name { get; protected set; } diff --git a/runtime/common/reflection/VeinTypeCode.cs b/runtime/common/reflection/VeinTypeCode.cs index fccd8df4..1f4ebd4c 100644 --- a/runtime/common/reflection/VeinTypeCode.cs +++ b/runtime/common/reflection/VeinTypeCode.cs @@ -244,6 +244,7 @@ public static bool HasNumber(this VeinTypeCode code) => TYPE_I8 => (x) => x.Int64Class, TYPE_STRING => (x) => x.StringClass, TYPE_FUNCTION => (x) => x.FunctionClass, + TYPE_RAW => (x) => x.RawClass, _ => throw new ArgumentOutOfRangeException(nameof(code), code, null) }; diff --git a/runtime/ishtar.base/emit/ClassBuilder.cs b/runtime/ishtar.base/emit/ClassBuilder.cs index 63dff6c0..ae0c0b74 100644 --- a/runtime/ishtar.base/emit/ClassBuilder.cs +++ b/runtime/ishtar.base/emit/ClassBuilder.cs @@ -55,7 +55,7 @@ internal ClassBuilder(VeinModuleBuilder module, QualityTypeName name, VeinClass /// /// Method name will be interned. /// - public MethodBuilder DefineMethod(string name, VeinClass returnType, params VeinArgumentRef[] args) + public MethodBuilder DefineMethod(string name, VeinComplexType returnType, params VeinArgumentRef[] args) { moduleBuilder.InternString(name); var method = new MethodBuilder(this, name, returnType, args); diff --git a/runtime/ishtar.base/emit/ILGenerator.cs b/runtime/ishtar.base/emit/ILGenerator.cs index 67069b75..80710a46 100644 --- a/runtime/ishtar.base/emit/ILGenerator.cs +++ b/runtime/ishtar.base/emit/ILGenerator.cs @@ -300,7 +300,7 @@ public virtual ILGenerator Emit(OpCode opcode, VeinMethod method) { if (method is null) throw new ArgumentNullException(nameof(method)); - if (opcode != OpCodes.CALL) + if (opcode != OpCodes.CALL && opcode != OpCodes.LDFN) throw new InvalidOpCodeException($"Opcode '{opcode.Name}' is not allowed."); using var _ = ILCapacityValidator.Begin(ref _position, opcode); diff --git a/runtime/ishtar.base/emit/MethodBuilder.cs b/runtime/ishtar.base/emit/MethodBuilder.cs index bf3ab736..50656400 100644 --- a/runtime/ishtar.base/emit/MethodBuilder.cs +++ b/runtime/ishtar.base/emit/MethodBuilder.cs @@ -17,7 +17,7 @@ internal VeinModuleBuilder moduleBuilder private readonly ILGenerator _generator; - internal MethodBuilder(ClassBuilder clazz, string name, VeinClass returnType, params VeinArgumentRef[] args) + internal MethodBuilder(ClassBuilder clazz, string name, VeinComplexType returnType, params VeinArgumentRef[] args) : base(name, 0, returnType, clazz, args) { classBuilder = clazz; diff --git a/runtime/ishtar.base/emit/VeinModuleBuilder.cs b/runtime/ishtar.base/emit/VeinModuleBuilder.cs index 3dea961a..75934450 100644 --- a/runtime/ishtar.base/emit/VeinModuleBuilder.cs +++ b/runtime/ishtar.base/emit/VeinModuleBuilder.cs @@ -68,6 +68,21 @@ public ClassBuilder DefineClass(QualityTypeName name) return c; } + /// + /// Define class by name. + /// + public ClassBuilder DefineClass(QualityTypeName name, VeinClass parent) + { + if (class_table.Any(x => x.FullName.Equals(name))) + throw new DuplicateNameException($"Class '{name}' already defined."); + InternString(name.Name); + InternString(name.Namespace); + InternString(name.AssemblyName); + var c = new ClassBuilder(this, name, parent); + class_table.Add(c); + return c; + } + private int _intern(Dictionary storage, T val) { var (key, value) = storage.FirstOrDefault(x => x.Value.Equals(val)); diff --git a/runtime/ishtar.generator/GeneratorContext.cs b/runtime/ishtar.generator/GeneratorContext.cs index 0bdfc584..bb3ddc5d 100644 --- a/runtime/ishtar.generator/GeneratorContext.cs +++ b/runtime/ishtar.generator/GeneratorContext.cs @@ -3,13 +3,19 @@ namespace ishtar; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Intrinsics.Arm; +using System.Security.Claims; +using System.Text; using emit; using Spectre.Console; using Sprache; +using vein.extensions; using vein.reflection; using vein.runtime; using vein.syntax; using Xunit; +using static vein.runtime.MethodFlags; +using static vein.runtime.VeinTypeCode; public record GeneratorContextConfig(bool DisableOptimization) { @@ -83,7 +89,25 @@ public ClassBuilder CreateHiddenType(string name) var b = Module.DefineClass(fullName); - b.Flags |= ClassFlags.Internal; + b.Flags |= ClassFlags.Internal | ClassFlags.Special; + + Classes.Add(b.FullName, b); + + return b; + } + + public ClassBuilder CreateHiddenType(string name, VeinClass parent) + { + QualityTypeName fullName = $"{Module.Name}%global::internal/{name}"; + + var currentType = Module.FindType(fullName, false, false); + + if (currentType is not UnresolvedVeinClass) + return Assert.IsType(currentType); + + var b = Module.DefineClass(fullName, parent); + + b.Flags |= ClassFlags.Internal | ClassFlags.Special; Classes.Add(b.FullName, b); @@ -129,9 +153,76 @@ public VeinComplexType ResolveScopedIdentifierType(IdentifierExpression id) var modType = Module.FindType(id.ExpressionString, Classes[CurrentMethod.Owner.FullName].Includes, false); if (modType is not null) return modType; + var methods = CurrentMethod.Owner.FindAnyMethods(id.ExpressionString); + if (methods.Count > 1) + { + this.LogError($"In the current context detected multiple methods with name '{id}'", id); + throw new SkipStatementException(); + } + if (methods.Count == 1) + return CreateFunctionMulticastGroup(methods.Single().Signature); + this.LogError($"The name '{id}' does not exist in the current context.", id); throw new SkipStatementException(); } + + public VeinClass CreateFunctionMulticastGroup(VeinMethodSignature sig) + { + var @base = CurrentScope.Context.Module + .FindType(new QualityTypeName("std", "FunctionMulticast", "global::std"), + true, true); + + var hiddenClass = CurrentScope.Context + .CreateHiddenType($"fn_{string.Join(' ', Encoding.UTF8.GetBytes(sig.ToTemplateString()).Select(x => $"{x:X}"))}", @base); + + if (hiddenClass.TypeCode is TYPE_FUNCTION) + return hiddenClass; + + + var types = CurrentScope.Context.Module.Types; + + hiddenClass.TypeCode = TYPE_FUNCTION; + + var objType = TYPE_OBJECT.AsClass(types); + var rawType = TYPE_RAW.AsClass(types); + + var ctorMethod = hiddenClass.DefineMethod(VeinMethod.METHOD_NAME_CONSTRUCTOR, TYPE_VOID.AsClass(types), [ + new("fn", rawType), + new("scope",objType) + ]); + + var scope = hiddenClass.DefineField("_scope", FieldFlags.Internal, objType); + var ptrRef = hiddenClass.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 = hiddenClass.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); + + return hiddenClass; + } + + public VeinField ResolveField(VeinClass targetType, IdentifierExpression target, IdentifierExpression id) { var field = targetType.FindField(id.ExpressionString); diff --git a/runtime/ishtar.generator/generators/access.cs b/runtime/ishtar.generator/generators/access.cs index c6877410..65c05223 100644 --- a/runtime/ishtar.generator/generators/access.cs +++ b/runtime/ishtar.generator/generators/access.cs @@ -164,7 +164,7 @@ public static ILGenerator EmitAccess(this ILGenerator gen, AccessExpressionSynta // literal access call if (access is { Left: LiteralExpressionSyntax literal, Right: InvocationExpression invoke1 }) { - var @class = literal.GetTypeCode().AsClass()(Types.Storage); + var @class = literal.GetTypeCode(ctx).AsClass()(Types.Storage); return gen.EmitLiteral(literal).EmitCall(@class, invoke1); } diff --git a/runtime/ishtar.generator/generators/call.cs b/runtime/ishtar.generator/generators/call.cs index ddfe8403..87219880 100644 --- a/runtime/ishtar.generator/generators/call.cs +++ b/runtime/ishtar.generator/generators/call.cs @@ -1,5 +1,8 @@ namespace ishtar; - +#nullable enable +using System; +using System.Linq; +using System.Security.Claims; using emit; using vein.runtime; using vein.syntax; @@ -10,6 +13,23 @@ public static ILGenerator EmitCall(this ILGenerator gen, VeinClass @class, Invoc { var ctx = gen.ConsumeFromMetadata("context"); + if (ctx.IsCallingDelegate(invocation, out var argument)) + { + foreach (var arg in invocation.Arguments) + gen.EmitExpression(arg); + var internalMethod = argument!.Type.FindMethod("invoke") ; + + if (internalMethod is null) + { + ctx.LogError($"Bad '{argument!.Type.FullName}' function class.", invocation); + throw new SkipStatementException(); + } + + gen.Emit(OpCodes.CALL, internalMethod); + return gen; + } + + var method = ctx.ResolveMethod(@class, invocation); var args = invocation.Arguments; @@ -20,6 +40,21 @@ public static ILGenerator EmitCall(this ILGenerator gen, VeinClass @class, Invoc return gen; } + public static bool IsCallingDelegate(this GeneratorContext gen, InvocationExpression invocation, out VeinArgumentRef? arg) + { + arg = gen.CurrentMethod.Signature.Arguments + .Where(x => !x.IsGeneric) + .FirstOrDefault(x => x.Name.Equals(invocation.Name.ExpressionString)); + + if (arg is null) + return false; + if (arg.IsGeneric) + return false; + if (arg.Type.TypeCode is VeinTypeCode.TYPE_FUNCTION) + return true; + return false; + } + public static ILGenerator EmitCallProperty(this ILGenerator gen, VeinClass @class, params IdentifierExpression[] chain) { var ctx = gen.ConsumeFromMetadata("context"); diff --git a/runtime/ishtar.generator/generators/emitters.cs b/runtime/ishtar.generator/generators/emitters.cs index ba8ba8e3..3e69c1f1 100644 --- a/runtime/ishtar.generator/generators/emitters.cs +++ b/runtime/ishtar.generator/generators/emitters.cs @@ -89,7 +89,7 @@ public static void EmitCreateObject(this ILGenerator gen, NewExpressionSyntax @n gen.Emit(OpCodes.NEWOBJ, type); foreach (var arg in args) gen.EmitExpression(arg); - var ctor = type.FindMethod("ctor", args.DetermineTypes(context)); + var ctor = type.FindMethod(VeinMethod.METHOD_NAME_CONSTRUCTOR, args.DetermineTypes(context)); if (ctor is null) { diff --git a/runtime/ishtar.generator/generators/operators.cs b/runtime/ishtar.generator/generators/operators.cs index 0f5a4e58..a986e8d1 100644 --- a/runtime/ishtar.generator/generators/operators.cs +++ b/runtime/ishtar.generator/generators/operators.cs @@ -10,6 +10,7 @@ namespace ishtar; using System.Linq; using vein; using vein.extensions; +using InvocationExpression = vein.syntax.InvocationExpression; public static class G_Operators { @@ -242,6 +243,8 @@ bool shot_load_self(bool yes = false) public static ILGenerator EmitUnary(this ILGenerator gen, UnaryExpressionSyntax node) { + var ctx = gen.ConsumeFromMetadata("context"); + if (node.OperatorType == ExpressionType.NegateChecked && node.Operand.GetTypeCode().HasInteger()) { var type = node.Operand.GetTypeCode(); @@ -263,6 +266,38 @@ public static ILGenerator EmitUnary(this ILGenerator gen, UnaryExpressionSyntax var operand_assign = new BinaryExpressionSyntax(node.Operand, addOne); gen.EmitAssignExpression(operand_assign); } + else if (node.OperatorType == ExpressionType.And && node.Operand.GetTypeCode(ctx) == VeinTypeCode.TYPE_FUNCTION) + { + var fnType = node.Operand.GetType(ctx); + + var invokeMethod = fnType.FindMethod("invoke"); + + + + gen.Emit(OpCodes.NEWOBJ, fnType); + gen.Emit(OpCodes.LDNULL); + + if (node.Operand is IdentifierExpression id) + { + var method = ctx.CurrentMethod.Owner.FindMethod(id.ExpressionString, invokeMethod.Signature.Arguments.Select(x => x.ComplexType)); + + gen.Emit(OpCodes.LDFN, method); + } + else + throw new NotSupportedException("EmitLoadFunction"); + + + var ctor = fnType.FindMethod(VeinMethod.METHOD_NAME_CONSTRUCTOR, + [ + VeinTypeCode.TYPE_RAW.AsClass(ctx.Module.Types), + VeinTypeCode.TYPE_OBJECT.AsClass(ctx.Module.Types) + ]); + + + + gen.Emit(OpCodes.CALL, ctor); + } + else throw new NotSupportedException("EmitUnary"); diff --git a/runtime/ishtar.generator/generators/types.cs b/runtime/ishtar.generator/generators/types.cs index f3c5704c..69e9a8d4 100644 --- a/runtime/ishtar.generator/generators/types.cs +++ b/runtime/ishtar.generator/generators/types.cs @@ -2,6 +2,7 @@ namespace ishtar; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using vein.runtime; @@ -9,7 +10,7 @@ namespace ishtar; public static class G_Types { - public static VeinTypeCode GetTypeCode(this ExpressionSyntax exp) + public static VeinTypeCode GetTypeCode(this ExpressionSyntax exp, GeneratorContext? gen = null) { if (exp is NumericLiteralExpressionSyntax num) return GetTypeCodeFromNumber(num); @@ -19,9 +20,55 @@ public static VeinTypeCode GetTypeCode(this ExpressionSyntax exp) return VeinTypeCode.TYPE_STRING; if (exp is NullLiteralExpressionSyntax) return VeinTypeCode.TYPE_NONE; + if (exp is IdentifierExpression id && gen is not null) + { + try + { + var t = id.DetermineType(gen); + + if (t.IsGeneric) + return VeinTypeCode.TYPE_CLASS; + return t.Class.TypeCode; + } + catch (Exception e) + { + Debug.WriteLine(e); + } + } + return VeinTypeCode.TYPE_CLASS; } + public static VeinClass GetType(this ExpressionSyntax exp, GeneratorContext gen) + { + if (exp is NumericLiteralExpressionSyntax num) + return GetTypeCodeFromNumber(num).AsClass(gen.Module.Types); + if (exp is BoolLiteralExpressionSyntax) + return VeinTypeCode.TYPE_BOOLEAN.AsClass(gen.Module.Types); + if (exp is StringLiteralExpressionSyntax) + return VeinTypeCode.TYPE_STRING.AsClass(gen.Module.Types); + if (exp is NullLiteralExpressionSyntax) + throw new NotSupportedException("NULL is not a type"); + if (exp is IdentifierExpression id && gen is not null) + { + try + { + var t = id.DetermineType(gen); + + if (t.IsGeneric) + throw new NotSupportedException($"Cannot summon type from generic declaration"); + return t.Class; + } + catch (Exception e) + { + Debug.WriteLine(e); + } + } + + throw new NotImplementedException(); + } + + public static (VeinClass, VeinClass) Fusce(this BinaryExpressionSyntax binary, GeneratorContext context) { var lt = binary.Left.DetermineType(context); @@ -132,8 +179,34 @@ public static VeinComplexType DetermineType(this ExpressionSyntax exp, Generator } if (exp is UnaryExpressionSyntax unary) { + if (unary.Kind == SyntaxType.PostfixUnaryExpression) + { + if (unary.Operand is not IdentifierExpression name) + { + context.LogError($"PostfixUnary cannot determine expression. support only IdentifierExpression operand", exp); + throw new SkipStatementException(); + } + var type = context.ResolveScopedIdentifierType(name); + + if (type.IsGeneric) + { + context.LogError($"PostfixUnary expression cannot user with Generic Type. support only Function expression operand", exp); + throw new SkipStatementException(); + } + + if (type.Class.TypeCode != VeinTypeCode.TYPE_FUNCTION) + { + context.LogError($"PostfixUnary expression cannot user with non function type. support only Function expression operand", exp); + throw new SkipStatementException(); + } + + return type; + } + if (unary.OperatorType.IsLogic()) return VeinTypeCode.TYPE_BOOLEAN.AsClass()(Types.Storage); + + // todo } context.LogError($"Cannot determine expression.", exp);