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

Userdefined classes #383

Draft
wants to merge 61 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
70ed34f
Update Syntax.xml
LPeter1997 Nov 29, 2023
e998221
Update Syntax.xml
LPeter1997 Nov 29, 2023
0d837fd
Update Syntax.xml
LPeter1997 Nov 29, 2023
d010bed
Update Syntax.xml
LPeter1997 Nov 29, 2023
c6b5236
Added keywords
LPeter1997 Nov 30, 2023
0313e1f
Update Parser.cs
LPeter1997 Nov 30, 2023
ad6f290
Update Parser.cs
LPeter1997 Nov 30, 2023
c975199
Parsing mostly done
LPeter1997 Dec 1, 2023
a9e6ca8
Update SyntaxFacts.cs
LPeter1997 Dec 1, 2023
df07111
Added class declaration
LPeter1997 Dec 2, 2023
c29ac8b
Added basic class symbol
LPeter1997 Dec 2, 2023
d6572c3
Added a devhost project for easier testing
LPeter1997 Dec 2, 2023
96add9a
Update SourceClassSymbol.cs
LPeter1997 Dec 2, 2023
968fbf5
Update MetadataSymbol.cs
LPeter1997 Dec 2, 2023
d93d474
Update SourceClassSymbol.cs
LPeter1997 Dec 3, 2023
b093f5c
Added default ctor symbol
LPeter1997 Dec 3, 2023
e3c6875
Update Program.cs
LPeter1997 Dec 3, 2023
295e607
Create IClass.cs
LPeter1997 Dec 3, 2023
6135261
Update IClass.cs
LPeter1997 Dec 3, 2023
fd81bc1
Added a basic, empty impl
LPeter1997 Dec 3, 2023
9f10f29
Changed ctors to procedures
LPeter1997 Dec 3, 2023
7dbd863
Update DefaultConstructorSymbol.cs
LPeter1997 Dec 3, 2023
3f4239b
Added to the codegen flow
LPeter1997 Dec 3, 2023
45701be
Added class to module
LPeter1997 Dec 3, 2023
769fb32
Fixed ToString
LPeter1997 Dec 4, 2023
04eea0a
Update MetadataCodegen.cs
LPeter1997 Dec 4, 2023
f950ba4
Merge branch 'main' into userdefined-classes
LPeter1997 Dec 16, 2023
8836428
Fix
LPeter1997 Dec 16, 2023
3bb41d0
Added base call
LPeter1997 Dec 16, 2023
213a498
Update ModuleCodegen.cs
LPeter1997 Dec 16, 2023
32fdbd6
Generating default ctor in IL
LPeter1997 Dec 16, 2023
5dde636
Generating default ctor
LPeter1997 Dec 16, 2023
44468e8
Update DefaultConstructorSymbol.cs
LPeter1997 Dec 16, 2023
8d9bda3
Update ClassCodegen.cs
LPeter1997 Dec 17, 2023
21f57dc
Added all required attribs
LPeter1997 Dec 17, 2023
a72eead
Update DefaultConstructorSymbol.cs
LPeter1997 Dec 17, 2023
47bf4f4
Can almost invoke ctor function
LPeter1997 Dec 17, 2023
d274496
Compiles
LPeter1997 Dec 18, 2023
b21586f
Started on primary ctor
LPeter1997 Dec 19, 2023
729fc5e
Primary ctor binds, compile fails
LPeter1997 Dec 19, 2023
7607ae9
Update SourcePrimaryConstructorSymbol.cs
LPeter1997 Dec 19, 2023
8210aed
Started on field
LPeter1997 Dec 19, 2023
3ee9908
Fields generate in metadata
LPeter1997 Dec 19, 2023
80c58de
Update SourcePrimaryConstructorSymbol.cs
LPeter1997 Dec 19, 2023
76d4e61
Create SourceAutoPropertySymbol.cs
LPeter1997 Dec 21, 2023
388c60e
Update SourceAutoPropertySymbol.cs
LPeter1997 Dec 21, 2023
f75bf73
Update SourceAutoPropertySymbol.cs
LPeter1997 Dec 21, 2023
dcc8b99
Added backing field
LPeter1997 Dec 21, 2023
a5aa66e
Updates
LPeter1997 Dec 21, 2023
9b19a89
Mostly working props
LPeter1997 Dec 21, 2023
7f80da0
Update MetadataCodegen.cs
LPeter1997 Dec 21, 2023
cbfe3b1
Update SourceModuleSymbol.cs
LPeter1997 Dec 23, 2023
413e267
Update FunctionBodyCodegen.cs
LPeter1997 Dec 23, 2023
86f4534
Update ArrayConstructorSymbol.cs
LPeter1997 Dec 23, 2023
817b0cb
Started on struct
LPeter1997 Dec 23, 2023
b18f12f
Update MetadataCodegen.cs
LPeter1997 Dec 23, 2023
921bb21
Update MetadataCodegen.cs
LPeter1997 Dec 23, 2023
54690cd
Update SynthetizedThisParameterSymbol.cs
LPeter1997 Dec 24, 2023
22622e9
Update SourcePrimaryConstructorSymbol.cs
LPeter1997 Dec 24, 2023
af8935d
Merge branch 'main' into userdefined-classes
Kuinox Jun 4, 2024
338b0fa
Updated old API usage.
Kuinox Jun 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/Draco.Compiler.DevHost/Draco.Compiler.DevHost.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Draco.Compiler\Draco.Compiler.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.1" />
</ItemGroup>

</Project>
226 changes: 226 additions & 0 deletions src/Draco.Compiler.DevHost/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.CommandLine;
using System.IO;
using System.Linq;
using Draco.Compiler.Api;
using Draco.Compiler.Api.Diagnostics;
using Draco.Compiler.Api.Scripting;
using Draco.Compiler.Api.Syntax;
using static Basic.Reference.Assemblies.Net70;

namespace Draco.Compiler.DevHost;

internal class Program
{
private static IEnumerable<MetadataReference> BclReferences => Basic.Reference.Assemblies.Net70.ReferenceInfos.All
.Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes)));

internal static int Main(string[] args) =>
ConfigureCommands().Invoke(args);

private static RootCommand ConfigureCommands()
{
var fileArgument = new Argument<FileInfo>("source file", description: "The Draco source file");
var outputOption = new Option<FileInfo>(new string[] { "-o", "--output" }, () => new FileInfo("output"), "Specifies the output file");
var optionalOutputOption = new Option<FileInfo?>(new string[] { "-o", "--output" }, () => null, "Specifies the (optional) output file");
var referencesOption = new Option<FileInfo[]>(new string[] { "-r", "--reference" }, Array.Empty<FileInfo>, "Specifies additional assembly references to use when compiling");
var filesArgument = new Argument<FileInfo[]>("source files", Array.Empty<FileInfo>, "Specifies draco source files that should be compiled");
var rootModuleOption = new Option<DirectoryInfo?>(new string[] { "-m", "--root-module" }, () => null, "Specifies the root module folder of the compiled files");

// Compile

var compileCommand = new Command("compile", "Compiles the Draco program")
{
filesArgument,
outputOption,
rootModuleOption,
referencesOption,
};
compileCommand.SetHandler(CompileCommand, filesArgument, outputOption, rootModuleOption, referencesOption);

// Run

var runCommand = new Command("run", "Runs the Draco program")
{
filesArgument,
rootModuleOption,
referencesOption,
};
runCommand.SetHandler(RunCommand, filesArgument, rootModuleOption, referencesOption);

// IR code

var irCommand = new Command("ir", "Generates the intermediate-representation of the Draco program")
{
filesArgument,
rootModuleOption,
optionalOutputOption,
};
irCommand.SetHandler(IrCommand, filesArgument, rootModuleOption, optionalOutputOption);

// Symbol tree

var symbolsCommand = new Command("symbols", "Prints the symbol-tree of the program")
{
filesArgument,
rootModuleOption,
optionalOutputOption,
};
symbolsCommand.SetHandler(SymbolsCommand, filesArgument, rootModuleOption, optionalOutputOption);

// Declaration tree

var declarationsCommand = new Command("declarations", "Prints the declarations-tree of the program")
{
filesArgument,
rootModuleOption,
optionalOutputOption,
};
declarationsCommand.SetHandler(DeclarationsCommand, filesArgument, rootModuleOption, optionalOutputOption);

// Formatting

var formatCommand = new Command("format", "Formats contents of the specified Draco file")
{
fileArgument,
optionalOutputOption,
};
formatCommand.SetHandler(FormatCommand, fileArgument, optionalOutputOption);

return new RootCommand("CLI for the Draco compiler")
{
compileCommand,
runCommand,
irCommand,
symbolsCommand,
declarationsCommand,
formatCommand
};
}

private static void CompileCommand(FileInfo[] input, FileInfo output, DirectoryInfo? rootModule, FileInfo[] references)
{
var syntaxTrees = GetSyntaxTrees(input);
var (path, name) = ExtractOutputPathAndName(output);
var compilation = Compilation.Create(
syntaxTrees: syntaxTrees,
metadataReferences: references
.Select(r => MetadataReference.FromPeStream(r.OpenRead()))
.Concat(BclReferences)
.ToImmutableArray(),
rootModulePath: rootModule?.FullName,
outputPath: path,
assemblyName: name);
using var peStream = new FileStream(Path.ChangeExtension(output.FullName, ".dll"), FileMode.OpenOrCreate);
using var pdbStream = new FileStream(Path.ChangeExtension(output.FullName, ".pdb"), FileMode.OpenOrCreate);
var emitResult = compilation.Emit(
peStream: peStream,
pdbStream: pdbStream);
EmitDiagnostics(emitResult);
}

private static void RunCommand(FileInfo[] input, DirectoryInfo? rootModule, FileInfo[] references)
{
var syntaxTrees = GetSyntaxTrees(input);
var compilation = Compilation.Create(
syntaxTrees: syntaxTrees,
metadataReferences: references
.Select(r => MetadataReference.FromPeStream(r.OpenRead()))
.Concat(BclReferences)
.ToImmutableArray(),
rootModulePath: rootModule?.FullName);
var execResult = ScriptingEngine.Execute(compilation);
if (!EmitDiagnostics(execResult))
{
Console.WriteLine($"Result: {execResult.Result}");
}
}

private static void IrCommand(FileInfo[] input, DirectoryInfo? rootModule, FileInfo? output)
{
var syntaxTrees = GetSyntaxTrees(input);
var compilation = Compilation.Create(
syntaxTrees: syntaxTrees,
// TODO: Add references from CLI?
metadataReferences: BclReferences.ToImmutableArray(),
rootModulePath: rootModule?.FullName);
using var irStream = OpenOutputOrStdout(output);
var emitResult = compilation.Emit(irStream: irStream);
EmitDiagnostics(emitResult);
}

private static void SymbolsCommand(FileInfo[] input, DirectoryInfo? rootModule, FileInfo? output)
{
var syntaxTrees = GetSyntaxTrees(input);
var compilation = Compilation.Create(
syntaxTrees: syntaxTrees,
rootModulePath: rootModule?.FullName);
using var symbolsStream = OpenOutputOrStdout(output);
var emitResult = compilation.Emit(symbolTreeStream: symbolsStream);
EmitDiagnostics(emitResult);
}

private static void DeclarationsCommand(FileInfo[] input, DirectoryInfo? rootModule, FileInfo? output)
{
var syntaxTrees = GetSyntaxTrees(input);
var compilation = Compilation.Create(
syntaxTrees: syntaxTrees,
rootModulePath: rootModule?.FullName);
using var declarationStream = OpenOutputOrStdout(output);
var emitResult = compilation.Emit(declarationTreeStream: declarationStream);
EmitDiagnostics(emitResult);
}

private static void FormatCommand(FileInfo input, FileInfo? output)
{
var syntaxTree = GetSyntaxTrees(input).First();
using var outputStream = OpenOutputOrStdout(output);
new StreamWriter(outputStream).Write(syntaxTree.Format().ToString());
}

private static ImmutableArray<SyntaxTree> GetSyntaxTrees(params FileInfo[] input)
{
var result = ImmutableArray.CreateBuilder<SyntaxTree>();
foreach (var file in input)
{
var sourceText = SourceText.FromFile(file.FullName);
result.Add(SyntaxTree.Parse(sourceText));
}
return result.ToImmutable();
}

private static bool EmitDiagnostics(EmitResult result)
{
if (result.Success) return false;
foreach (var diag in result.Diagnostics)
{
Console.Error.WriteLine(diag.ToString());
}
return true;
}

private static bool EmitDiagnostics<T>(ExecutionResult<T> result)
{
if (result.Success) return false;
foreach (var diag in result.Diagnostics)
{
Console.Error.WriteLine(diag.ToString());
}
return true;
}

private static (string Path, string Name) ExtractOutputPathAndName(FileInfo outputInfo)
{
var outputPath = outputInfo.FullName;
var path = Path.GetDirectoryName(outputPath) ?? string.Empty;
path = Path.GetFullPath(path);
var name = Path.GetFileNameWithoutExtension(outputPath) ?? string.Empty;
return (path, name);
}

private static Stream OpenOutputOrStdout(FileInfo? output) => output is null
? Console.OpenStandardOutput()
: output.Open(FileMode.OpenOrCreate, FileAccess.Write);
}
3 changes: 3 additions & 0 deletions src/Draco.Compiler/Api/Syntax/SyntaxFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ public static class SyntaxFacts
TokenKind.EndOfInput => string.Empty,
TokenKind.InterpolationEnd => "}",
TokenKind.KeywordAnd => "and",
TokenKind.KeywordClass => "class",
TokenKind.KeywordElse => "else",
TokenKind.KeywordFalse => "false",
TokenKind.KeywordField => "field",
TokenKind.KeywordFor => "for",
TokenKind.KeywordFunc => "func",
TokenKind.KeywordGoto => "goto",
Expand All @@ -36,6 +38,7 @@ public static class SyntaxFacts
TokenKind.KeywordReturn => "return",
TokenKind.KeywordTrue => "true",
TokenKind.KeywordVal => "val",
TokenKind.KeywordValue => "value",
TokenKind.KeywordVar => "var",
TokenKind.KeywordWhile => "while",
TokenKind.ParenOpen => "(",
Expand Down
15 changes: 15 additions & 0 deletions src/Draco.Compiler/Api/Syntax/TokenKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public enum TokenKind
/// </summary>
KeywordAnd,

/// <summary>
/// The keyword 'class'.
/// </summary>
KeywordClass,

/// <summary>
/// The keyword 'else'.
/// </summary>
Expand All @@ -90,6 +95,11 @@ public enum TokenKind
/// </summary>
KeywordFalse,

/// <summary>
/// The keyword 'field'.
/// </summary>
KeywordField,

/// <summary>
/// The keyword 'for'.
/// </summary>
Expand Down Expand Up @@ -170,6 +180,11 @@ public enum TokenKind
/// </summary>
KeywordVal,

/// <summary>
/// The keyword 'value'.
/// </summary>
KeywordValue,

/// <summary>
/// The keyword 'var'.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Draco.Compiler/Internal/Binding/LocalBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private void Build()
private Symbol? BuildSymbol(SyntaxNode syntax, int localCount) => syntax switch
{
FunctionDeclarationSyntax function => new SourceFunctionSymbol(this.ContainingSymbol, function),
ParameterSyntax parameter => new SourceParameterSymbol(this.ContainingSymbol, parameter),
ParameterSyntax parameter => new SourceParameterSymbol((FunctionSymbol)this.ContainingSymbol, parameter),
VariableDeclarationSyntax variable => new SourceLocalSymbol(this.ContainingSymbol, new TypeVariable(localCount), variable),
LabelDeclarationSyntax label => new SourceLabelSymbol(this.ContainingSymbol, label),
_ => null,
Expand Down
4 changes: 3 additions & 1 deletion src/Draco.Compiler/Internal/Codegen/CilCodegen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ public CilCodegen(MetadataCodegen metadataCodegen, IProcedure procedure)
private EntityHandle GetHandle(Symbol symbol) => this.metadataCodegen.GetEntityHandle(symbol);

// TODO: Parameters don't handle unit yet, it introduces some signature problems
private int GetParameterIndex(ParameterSymbol parameter) => this.procedure.GetParameterIndex(parameter);
private int GetParameterIndex(ParameterSymbol parameter) => parameter.IsThis
? 0
: this.procedure.GetParameterIndex(parameter) + (parameter.ContainingSymbol.IsStatic ? 0 : 1);

private AllocatedLocal? GetAllocatedLocal(LocalSymbol local)
{
Expand Down
Loading
Loading