From 991e13d6245e99e4a2ea986de91bc48d2e30cf05 Mon Sep 17 00:00:00 2001 From: Kuinox Date: Sun, 29 Sep 2024 00:14:56 +0200 Subject: [PATCH] wip --- .../EndToEnd/CodeExecutionTests.cs | 35 ++++++++ .../Internal/Binding/BinderCache.cs | 4 + .../Internal/Codegen/MetadataCodegen.cs | 89 +++++++++++++++++++ .../Internal/OptimizingIr/Model/IType.cs | 5 ++ src/Draco.Compiler/Internal/Syntax/Lexer.cs | 1 + 5 files changed, 134 insertions(+) create mode 100644 src/Draco.Compiler.Tests/EndToEnd/CodeExecutionTests.cs diff --git a/src/Draco.Compiler.Tests/EndToEnd/CodeExecutionTests.cs b/src/Draco.Compiler.Tests/EndToEnd/CodeExecutionTests.cs new file mode 100644 index 000000000..2d0512a21 --- /dev/null +++ b/src/Draco.Compiler.Tests/EndToEnd/CodeExecutionTests.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Draco.Compiler.Tests.TestUtilities; + +namespace Draco.Compiler.Tests.EndToEnd; + +[Collection(nameof(NoParallelizationCollectionDefinition))] +public class CodeExecutionTests +{ + [Fact] + public void ClassHelloWorld() + { + var assembly = CompileToAssembly(""" + import System.Console; + + func main() { + WriteLine("Hello, World!"); + } + + class Foo { + global func bar() { + WriteLine("Hello, World!"); + } + } + """); + + var stringWriter = new StringWriter(); + _ = Invoke(assembly: assembly, stdout: stringWriter); + + Assert.Equal($"Hello, World!{Environment.NewLine}", stringWriter.ToString(), ignoreLineEndingDifferences: true); + } +} diff --git a/src/Draco.Compiler/Internal/Binding/BinderCache.cs b/src/Draco.Compiler/Internal/Binding/BinderCache.cs index 5f7d5667e..c62da3d9a 100644 --- a/src/Draco.Compiler/Internal/Binding/BinderCache.cs +++ b/src/Draco.Compiler/Internal/Binding/BinderCache.cs @@ -25,6 +25,10 @@ internal sealed class BinderCache(Compilation compilation) /// The binder for . public Binder GetBinder(SyntaxNode syntax) { + if(syntax is ClassDeclarationSyntax ) + { + + } var scopeDefiningAncestor = BinderFacts.GetScopeDefiningAncestor(syntax); Debug.Assert(scopeDefiningAncestor is not null); diff --git a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs index ec5cab25a..93b23103d 100644 --- a/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs +++ b/src/Draco.Compiler/Internal/Codegen/MetadataCodegen.cs @@ -98,6 +98,7 @@ public static void Generate( private readonly Dictionary intrinsicReferenceHandles = []; private readonly AssemblyReferenceHandle systemRuntimeReference; private readonly TypeReferenceHandle systemObjectReference; + private readonly TypeReferenceHandle systemValueTypeReference; private MetadataCodegen(Compilation compilation, IAssembly assembly, CodegenFlags flags) { @@ -120,6 +121,11 @@ private MetadataCodegen(Compilation compilation, IAssembly assembly, CodegenFlag assembly: this.systemRuntimeReference, @namespace: "System", name: "Object"); + + this.systemValueTypeReference = this.GetOrAddTypeReference( + assembly: this.systemRuntimeReference, + @namespace: "System", + name: "ValueType"); } private void WriteModuleAndAssemblyDefinition() @@ -648,6 +654,89 @@ private BlobHandle EncodeAttributeSignature(AttributeInstance attribute) }); } + private TypeDefinitionHandle EncodeClass( + IType type, + TypeDefinitionHandle? parent, + ref int fieldIndex, + ref int procIndex + ) + { + var startFieldIndex = fieldIndex; + var startProcIndex = procIndex; + + var visibility = (type.Symbol.Visibility, parent) switch + { + (Api.Semantics.Visibility.Public, not null) => TypeAttributes.NestedPublic, + (Api.Semantics.Visibility.Public, null) => TypeAttributes.Public, + (_, not null) => TypeAttributes.NestedAssembly, + (_, null) => TypeAttributes.NotPublic, + }; + + var attributes = visibility | TypeAttributes.Class | TypeAttributes.AutoLayout | TypeAttributes.BeforeFieldInit | TypeAttributes.Sealed; + + if (type.Symbol.IsValueType) attributes |= TypeAttributes.SequentialLayout; // AutoLayout = 0. + + var createdClass = this.AddTypeDefinition( + attributes, + null, + type.Name, + type.Symbol.IsValueType ? this.systemValueTypeReference : this.systemObjectReference, + fieldList: MetadataTokens.FieldDefinitionHandle(startFieldIndex), + methodList: MetadataTokens.MethodDefinitionHandle(startProcIndex) + ); + + // Procedures + foreach (var proc in type.Methods.Values) + { + var handle = this.EncodeProcedure(proc); + ++procIndex; + + // Todo: properties + } + + // Fields + foreach (var field in type.Fields) + { + this.EncodeField(field.Key); + ++fieldIndex; + } + + // If this is a valuetype without fields, we add .pack 0 and .size 1 + if (type.Symbol.IsValueType && type.Fields.Count == 0) + { + this.MetadataBuilder.AddTypeLayout( + type: createdClass, + packingSize: 0, + size: 1); + } + + // If this isn't top level module, we specify nested relationship + if (parent is not null) this.MetadataBuilder.AddNestedType(createdClass, parent.Value); + + return createdClass; + } + + private FieldDefinitionHandle EncodeField(FieldSymbol field) + { + var visibility = field.Visibility switch + { + Api.Semantics.Visibility.Public => FieldAttributes.Public, + Api.Semantics.Visibility.Internal => FieldAttributes.Assembly, + Api.Semantics.Visibility.Private => FieldAttributes.Private, + _ => throw new IndexOutOfRangeException(nameof(field.Visibility)), + }; + var mutability = field.IsMutable ? default : FieldAttributes.InitOnly; + + // Definition + return this.AddFieldDefinition( + attributes: visibility | mutability, + name: field.Name, + signature: this.EncodeFieldSignature(field)); + } + + private BlobHandle EncodeFieldSignature(FieldSymbol field) => + this.EncodeBlob(e => this.EncodeSignatureType(e.Field().Type(), field.Type)); + private IEnumerable ScalarConstantTypes => [ this.WellKnownTypes.SystemSByte, this.WellKnownTypes.SystemInt16, diff --git a/src/Draco.Compiler/Internal/OptimizingIr/Model/IType.cs b/src/Draco.Compiler/Internal/OptimizingIr/Model/IType.cs index 82a57ea5f..b51770cd8 100644 --- a/src/Draco.Compiler/Internal/OptimizingIr/Model/IType.cs +++ b/src/Draco.Compiler/Internal/OptimizingIr/Model/IType.cs @@ -5,6 +5,11 @@ namespace Draco.Compiler.Internal.OptimizingIr.Model; internal interface IType { + /// + /// The symbol of this type. + /// + public TypeSymbol Symbol { get; } + /// /// The name of this type. /// diff --git a/src/Draco.Compiler/Internal/Syntax/Lexer.cs b/src/Draco.Compiler/Internal/Syntax/Lexer.cs index 63ffa00fe..96b598c17 100644 --- a/src/Draco.Compiler/Internal/Syntax/Lexer.cs +++ b/src/Draco.Compiler/Internal/Syntax/Lexer.cs @@ -331,6 +331,7 @@ Unit TakeWithText(TokenKind tokenKind, int length) { "and" => TokenKind.KeywordAnd, "class" => TokenKind.KeywordClass, + "global" => TokenKind.KeywordGlobal, "else" => TokenKind.KeywordElse, "false" => TokenKind.KeywordFalse, "for" => TokenKind.KeywordFor,