diff --git a/.Net Core Templates/templatepack.csproj b/.Net Core Templates/templatepack.csproj
index 9ecae706..4fb1b501 100644
--- a/.Net Core Templates/templatepack.csproj
+++ b/.Net Core Templates/templatepack.csproj
@@ -2,7 +2,7 @@
Template
- 1.0.60
+ 1.0.61
Backlang.Templates
Backlang Templates
furesoft
diff --git a/.Net Core Templates/templates/console/Program.back b/.Net Core Templates/templates/console/Program.back
index 74848074..765b79c1 100644
--- a/.Net Core Templates/templates/console/Program.back
+++ b/.Net Core Templates/templates/console/Program.back
@@ -1,6 +1,4 @@
-public static func main() -> i32
+func main()
{
print("Hello World");
-
- return 0;
}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index a03cb38a..2c6f4b0c 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -21,9 +21,9 @@ jobs:
- kind: macOS
os: macos-latest
target: osx-x64
-
+
runs-on: ${{ matrix.os }} # For a list of available runner types, refer to https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
-
+
steps:
- name: Checkout
uses: actions/checkout@v3
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 1e17ff16..ed1139b4 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -2,12 +2,12 @@ name: Tests
on:
push:
- branches:
+ branches:
- '*' # matches every branch that doesn't contain a '/'
- '*/*' # matches every branch containing a single '/'
- '**' # matches every branch
pull_request:
- branches:
+ branches:
- '*' # matches every branch that doesn't contain a '/'
- '*/*' # matches every branch containing a single '/'
- '**' # matches every branch
@@ -19,7 +19,7 @@ jobs:
env:
Solution_Name: Source/Backlang-Compiler.sln # Replace with your solution name, i.e. MyWpfApp.sln.
Test_Project_Path: Source/TestProject1/TestProject1.csproj # Replace with the path to your test project, i.e. MyWpfApp.Tests\MyWpfApp.Tests.csproj.
-
+
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -31,7 +31,10 @@ jobs:
with:
dotnet-version: 7.0.x
include-prerelease: true
-
+
+ - name: Install WASM
+ run: dotnet workload install wasm-tools
+
- name: Build
run: dotnet build $Solution_Name --configuration Release
diff --git a/.gitignore b/.gitignore
index 824d32e3..f8aef24a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -350,4 +350,4 @@ MigrationBackup/
.ionide/
*.vsix
-StreamPlan.txt
\ No newline at end of file
+*.dll
diff --git a/Source/.vscode/launch.json b/.vscode/launch.json
similarity index 55%
rename from Source/.vscode/launch.json
rename to .vscode/launch.json
index 594545c9..d5863821 100644
--- a/Source/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -9,16 +9,12 @@
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
- "program": "${workspaceFolder}/Backlang-Compiler/bin/Debug/net7.0/Backlang-Compiler.dll",
- "args": ["-i", "${workspaceFolder}/Backlang-Compiler/bin/Debug/net7.0/compilation.back", "-o", "compilation"],
+ "program": "${workspaceFolder}/Source/Backlang-Compiler/bin/Debug/net7.0/Backlang-Compiler.dll",
+ "args": ["-i", "${workspaceFolder}/Source/Backlang-Compiler/bin/Debug/net7.0/compilation.back", "-o", "compilation"],
"cwd": "${workspaceFolder}",
- "console": "internalConsole",
- "stopAtEntry": false
- },
- {
- "name": ".NET Core Attach",
- "type": "coreclr",
- "request": "attach"
+ "stopAtEntry": false,
+ "console": "internalConsole"
}
+
]
}
\ No newline at end of file
diff --git a/Source/.vscode/tasks.json b/.vscode/tasks.json
similarity index 96%
rename from Source/.vscode/tasks.json
rename to .vscode/tasks.json
index 31c32bd3..9ee9d4ad 100644
--- a/Source/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -9,6 +9,9 @@
"type": "shell",
"args": [
"build",
+
+ "Source/",
+
// Ask dotnet build to generate full paths for file names.
"/property:GenerateFullPaths=true",
// Do not generate summary otherwise it leads to duplicate errors in Problems panel
diff --git a/Source/Backlang-Compiler.sln b/Source/Backlang-Compiler.sln
index 6020586e..b387f7da 100644
--- a/Source/Backlang-Compiler.sln
+++ b/Source/Backlang-Compiler.sln
@@ -29,6 +29,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Backlang.Backends.Bs2k", "P
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Backlang.ResourcePreprocessor.Mif", "Plugins\Backlang.ResourcePreprocessor.Mif\Backlang.ResourcePreprocessor.Mif.csproj", "{F45724ED-51E7-4262-A94C-42C1F639E7AE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Backlang.WasmBridge", "Backlang.WasmBridge\Backlang.WasmBridge.csproj", "{DFA33B5E-1C8F-4930-9130-24C00D935919}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -71,6 +73,10 @@ Global
{F45724ED-51E7-4262-A94C-42C1F639E7AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F45724ED-51E7-4262-A94C-42C1F639E7AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F45724ED-51E7-4262-A94C-42C1F639E7AE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DFA33B5E-1C8F-4930-9130-24C00D935919}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DFA33B5E-1C8F-4930-9130-24C00D935919}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DFA33B5E-1C8F-4930-9130-24C00D935919}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DFA33B5E-1C8F-4930-9130-24C00D935919}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Source/Backlang-Compiler/Backlang-Compiler.csproj b/Source/Backlang-Compiler/Backlang-Compiler.csproj
index 90c73d84..0ae62399 100644
--- a/Source/Backlang-Compiler/Backlang-Compiler.csproj
+++ b/Source/Backlang-Compiler/Backlang-Compiler.csproj
@@ -13,10 +13,10 @@
-
-
-
-
+
+
+
+
@@ -29,9 +29,6 @@
Always
-
- Always
-
diff --git a/Source/Backlang-Compiler/Program.cs b/Source/Backlang-Compiler/Program.cs
index 0352ed33..8498b5dc 100644
--- a/Source/Backlang-Compiler/Program.cs
+++ b/Source/Backlang-Compiler/Program.cs
@@ -8,8 +8,13 @@ public static class Program
{
public static void Main(string[] args)
{
- Parser.Default.ParseArguments(args)
- .WithParsed(context => {
+ Parser.Default.ParseArguments(args)
+ .WithParsed(options => {
+ var context = new CompilerContext
+ {
+ Options = options
+ };
+
CompilerDriver.Compile(context);
});
}
diff --git a/Source/Backlang-Compiler/Properties/launchSettings.json b/Source/Backlang-Compiler/Properties/launchSettings.json
index 897e10f2..fbc368a8 100644
--- a/Source/Backlang-Compiler/Properties/launchSettings.json
+++ b/Source/Backlang-Compiler/Properties/launchSettings.json
@@ -2,7 +2,7 @@
"profiles": {
"Backlang-Compiler": {
"commandName": "Project",
- "commandLineArgs": "-i compilation.back -o compilation --target dotnet"
+ "commandLineArgs": "-i compilation.back -o compilation --target dotnet --framework net7.0"
}
}
}
\ No newline at end of file
diff --git a/Source/Backlang-Compiler/compilation.back b/Source/Backlang-Compiler/compilation.back
index 5309930f..ec2c5489 100644
--- a/Source/Backlang-Compiler/compilation.back
+++ b/Source/Backlang-Compiler/compilation.back
@@ -1,11 +1,11 @@
-import System;
-public struct Point
-{
- let callback: (i32, bool) -> none;
- let tuple: (i32, char);
- //let a: i32*; // this make a crashy crashy crash
-}
+func main() {
+ if true {
+ return 1;
+ }
+ else {
+ return 2;
+ }
-Main {
+ print("after");
}
\ No newline at end of file
diff --git a/Source/Backlang-Compiler/test.back b/Source/Backlang-Compiler/test.back
deleted file mode 100644
index c71e2968..00000000
--- a/Source/Backlang-Compiler/test.back
+++ /dev/null
@@ -1,103 +0,0 @@
-func main() {
- let something : i32* = 12;
- doSomething();
- return 0;
-}
-
-func print(value : T)
- T is i8-i32 {
-
-}
-
-class SomeModel : #ViewModel() {
- #notify(Name : string);
-}
-
-
-type int = i32;
-const bits = 32;
-
-global flags : Flags = #EAX;
-global behavior : Flags = &250;
-
-func doSomething() {
- print("Hello World");
- let arr = [12, 42, 3];
-
- print(arr[0]);
-
-
- /*
- multi
- line
- comment
- */
-
- while true {
- doSomething(2);
- }
-
- for x : i32 in 1..12 {
- print(x);
- }
-
- for x in arr {
- print(x);
- }
-}
-
-enum Colors {
- Red = 0xFF0000,
- Green = 0x00FF00,
- Blue = 0x0000FF
-}
-
-bitfield Flags {
- DivideByZero = 0,
- IsZero = 1,
-}
-
-enum Instructions {
- Invalid,
- Move = 1 << 12,
- Pop,
-}
-
-enum StringEnum : string {
- prefix = "Hello",
- suffix = "World",
-}
-
-func tests(something : i32) { //check if something is none, if not return none
-
- let kkk = sizeof;
- let mm : i32 = default;
- let mn = default;
-
- let a = 12;
- let mut b : i32 = 42;
- let c = &a;
-
- let d : list = [];
-
- let e = list> = [];
-
- a <-> b;
-
- a = b % 3;
-
- if a <= 12 and a >= 13 {
-
- }
- else {
-
- }
-
- let result = match a with
- 12 => 13,
- > 13 => 15,
- _ => 0,
- [1, .. , 3]; // need to be implemented
-
- return none;
-}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Backlang.Codeanalysis.csproj b/Source/Backlang.Codeanalysis/Backlang.Codeanalysis.csproj
index 380ce683..8f5261fd 100644
--- a/Source/Backlang.Codeanalysis/Backlang.Codeanalysis.csproj
+++ b/Source/Backlang.Codeanalysis/Backlang.Codeanalysis.csproj
@@ -18,6 +18,7 @@
+
True
@@ -27,8 +28,24 @@
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
diff --git a/Source/Backlang.Codeanalysis/Core/Attributes/BinaryOperatorInfoAttribute.cs b/Source/Backlang.Codeanalysis/Core/Attributes/BinaryOperatorInfoAttribute.cs
index 82bd78e4..0e51f25e 100644
--- a/Source/Backlang.Codeanalysis/Core/Attributes/BinaryOperatorInfoAttribute.cs
+++ b/Source/Backlang.Codeanalysis/Core/Attributes/BinaryOperatorInfoAttribute.cs
@@ -1,5 +1,4 @@
-using Backlang.Codeanalysis.Core.Attributes;
-using Backlang.Codeanalysis.Parsing.Precedences;
+using Backlang.Codeanalysis.Parsing.Precedences;
namespace Backlang.Codeanalysis.Core.Attributes;
@@ -13,5 +12,4 @@ public BinaryOperatorInfoAttribute(int precedence) : base(precedence, isUnary: f
public BinaryOperatorInfoAttribute(BinaryOpPrecedences precedence) : this((int)precedence)
{
}
-
-}
+}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Core/BaseLexer.cs b/Source/Backlang.Codeanalysis/Core/BaseLexer.cs
index c87e56e0..9348e31b 100644
--- a/Source/Backlang.Codeanalysis/Core/BaseLexer.cs
+++ b/Source/Backlang.Codeanalysis/Core/BaseLexer.cs
@@ -61,7 +61,7 @@ protected void ReportError()
_column++;
var range = SourceRange.New(_document, new IndexRange(_position, 1));
- Messages.Add(Message.Error($"Unknown Charakter '{Current()}'", range));
+ Messages.Add(Message.Error(new LocalizableString(ErrorID.UnknownCharacter, Current().ToString()), range));
Advance();
}
}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Core/ErrorID.cs b/Source/Backlang.Codeanalysis/Core/ErrorID.cs
new file mode 100644
index 00000000..f38e9301
--- /dev/null
+++ b/Source/Backlang.Codeanalysis/Core/ErrorID.cs
@@ -0,0 +1,37 @@
+namespace Backlang.Codeanalysis.Core;
+
+public enum ErrorID : int
+{
+ UnexpecedType = 0001,
+ InvalidModifierCombination = 0002,
+ UnknownCharacter = 0003,
+ UnterminatedCharLiteral = 0004,
+ UnknownExpression = 0005,
+ UnknownLiteral = 0006,
+ ForbiddenTrailingComma = 0007,
+ BitfieldNotLiteral = 0008,
+ UnexpecedTypeMember = 0009,
+ ExpectedTypeLiteral = 0010,
+ UnknownSwitchOption = 0011,
+ NoCatchBlock = 0012,
+ EmptyFile = 0013,
+ ExpectedIdentifier = 0014,
+ UnterminatedStringLiteral = 0015,
+ NotClosedMultilineComment = 0016,
+ Expected = 0017,
+ DuplicateModifier = 0018,
+ NamespaceAlreadyImported = 0019,
+ RunnableTypeButNoEntrypoint = 0020,
+ CannotBeFoundDidYouMean = 0021,
+ CannotImplementTypeNotFound = 0022,
+ CannotImplementUnitType = 0023,
+ AlreadyDeclared = 0024,
+ TypeMismatch = 0025,
+ UnitTypeMismatch = 0026,
+ CannotBeResolved = 0027,
+ CannotFindFunction = 0028,
+ TargetNotFound = 0029,
+ NotDefined = 0030,
+ CannotDeduceType = 31,
+ DeducingTypeNotPossible = 32,
+}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Core/LevensteinDistance.cs b/Source/Backlang.Codeanalysis/Core/LevensteinDistance.cs
index 8923202e..6f766472 100644
--- a/Source/Backlang.Codeanalysis/Core/LevensteinDistance.cs
+++ b/Source/Backlang.Codeanalysis/Core/LevensteinDistance.cs
@@ -6,23 +6,27 @@ public static int Calculate(string source, string target)
{
if (string.IsNullOrEmpty(source))
{
- if (string.IsNullOrEmpty(target)) return 0;
- return target.Length;
+ return string.IsNullOrEmpty(target) ? 0 : target.Length;
+ }
+
+ if (string.IsNullOrEmpty(target))
+ {
+ return source.Length;
}
- if (string.IsNullOrEmpty(target)) return source.Length;
if (source.Length > target.Length)
{
- var temp = target;
- target = source;
- source = temp;
+ (source, target) = (target, source);
}
var m = target.Length;
var n = source.Length;
var distance = new int[2, m + 1];
// Initialize the distance matrix
- for (var j = 1; j <= m; j++) distance[0, j] = j;
+ for (var j = 1; j <= m; j++)
+ {
+ distance[0, j] = j;
+ }
var currentRow = 0;
for (var i = 1; i <= n; ++i)
@@ -49,7 +53,10 @@ public static string Suggest(string source, IEnumerable possibilities)
foreach (var str in possibilities)
{
- if (str == "Main") continue;
+ if (str == "Main")
+ {
+ continue;
+ }
var distance = Calculate(source, str);
if (distance <= lastDistance)
diff --git a/Source/Backlang.Codeanalysis/Core/LocalizableString.cs b/Source/Backlang.Codeanalysis/Core/LocalizableString.cs
new file mode 100644
index 00000000..23261e2e
--- /dev/null
+++ b/Source/Backlang.Codeanalysis/Core/LocalizableString.cs
@@ -0,0 +1,53 @@
+using Backlang.Codeanalysis.Properties;
+using System.Resources;
+
+namespace Backlang.Codeanalysis.Core;
+
+public readonly struct LocalizableString
+{
+ public readonly ErrorID ErrorID;
+ public readonly string[] Arguments;
+ public readonly string FallbackValue;
+
+ private static readonly ResourceManager _resourceManager = new("Backlang.Codeanalysis.Properties.Resources", typeof(Resources).Assembly);
+
+ public LocalizableString(ErrorID errorID, params string[] arguments)
+ {
+ ErrorID = errorID;
+ Arguments = arguments;
+ FallbackValue = null;
+ }
+
+ public LocalizableString(ErrorID errorID) : this()
+ {
+ ErrorID = errorID;
+ Arguments = new[] { "NO_VALUE" };
+ }
+
+ public LocalizableString(string fallbackValue) : this()
+ {
+ FallbackValue = fallbackValue;
+ }
+
+ public static implicit operator string(LocalizableString lstr)
+ {
+ if (!string.IsNullOrEmpty(lstr.FallbackValue))
+ {
+ return lstr.FallbackValue;
+ }
+
+ var resourceID = $"BL({(int)lstr.ErrorID:D4})";
+
+ return string.Format(resourceID + ": " + _resourceManager.GetString(resourceID), args: lstr.Arguments);
+ }
+
+ public static implicit operator LocalizableString(ErrorID id)
+ {
+ return new(id);
+ }
+
+ public static implicit operator LocalizableString(string message)
+ {
+ return new(message);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Core/ParsingHelpers.cs b/Source/Backlang.Codeanalysis/Core/ParsingHelpers.cs
index 9a6071d1..fb106b1f 100644
--- a/Source/Backlang.Codeanalysis/Core/ParsingHelpers.cs
+++ b/Source/Backlang.Codeanalysis/Core/ParsingHelpers.cs
@@ -24,13 +24,15 @@ public static LNodeList ParseSeperated(
if (parser.Iterator.IsMatch(seperator) && parser.Iterator.Peek(1).Type == terminator)
{
- parser.Iterator.Messages.Add(Message.Error("Trailing comma is forbidden"));
+ parser.AddError(ErrorID.ForbiddenTrailingComma);
parser.Iterator.Match(seperator);
}
} while (parser.Iterator.ConsumeIfMatch(seperator));
if (consumeTerminator)
+ {
parser.Iterator.Match(terminator);
+ }
return list;
}
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/BitFieldMemberDeclaration.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/BitFieldMemberDeclaration.cs
index 1ae438df..6a3e77b1 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/BitFieldMemberDeclaration.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/BitFieldMemberDeclaration.cs
@@ -6,8 +6,7 @@ public sealed class BitFieldMemberDeclaration : IParsePoint
{
public static LNode Parse(TokenIterator iterator, Parser parser)
{
- Token nameToken = null;
-
+ Token nameToken;
if (iterator.Current.Type == TokenType.Identifier)
{
nameToken = iterator.Current;
@@ -25,7 +24,7 @@ public static LNode Parse(TokenIterator iterator, Parser parser)
if (!value[0].HasValue)
{
- iterator.Messages.Add(Message.Error("Bitfield member declaration only allows literals", value.Range));
+ parser.AddError(Core.ErrorID.BitfieldNotLiteral, value.Range);
}
return SyntaxTree.Factory.Tuple(SyntaxTree.Factory.Id(nameToken.Text).WithRange(nameToken), value);
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/EnumMemberDeclaration.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/EnumMemberDeclaration.cs
index 630ded87..f93ddcbd 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/EnumMemberDeclaration.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/EnumMemberDeclaration.cs
@@ -6,7 +6,7 @@ public class EnumMemberDeclaration : IParsePoint
{
public static LNode Parse(TokenIterator iterator, Parser parser)
{
- Annotation.TryParse(parser, out var annotations);
+ _ = Annotation.TryParse(parser, out var annotations);
var memberNameToken = iterator.Match(TokenType.Identifier);
LNode value = LNode.Missing;
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/ImplementationDeclaration.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/ImplementationDeclaration.cs
index 902a3d42..557f651c 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/ImplementationDeclaration.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/ImplementationDeclaration.cs
@@ -7,8 +7,6 @@ public class ImplementationDeclaration : IParsePoint
public static LNode Parse(TokenIterator iterator, Parser parser)
{
var keywordToken = iterator.Prev;
-
- LNode target = null;
var targets = new LNodeList();
while (iterator.Current.Type != TokenType.OpenCurly && !parser.Iterator.IsMatch(TokenType.EOF))
@@ -28,6 +26,7 @@ public static LNode Parse(TokenIterator iterator, Parser parser)
}
}
+ LNode target;
if (targets.Count == 1)
{
target = targets[0];
@@ -43,8 +42,8 @@ public static LNode Parse(TokenIterator iterator, Parser parser)
LNodeList body = new();
while (!parser.Iterator.IsMatch(TokenType.EOF) && iterator.Current.Type != TokenType.CloseCurly)
{
- Annotation.TryParse(parser, out var annotations);
- Modifier.TryParse(parser, out var modifiers);
+ _ = Annotation.TryParse(parser, out var annotations);
+ _ = Modifier.TryParse(parser, out var modifiers);
body.Add(parser.InvokeParsePoint(parser.DeclarationParsePoints).PlusAttrs(annotations).PlusAttrs(modifiers));
}
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/MacroBlockDeclaration.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/MacroBlockDeclaration.cs
index ccef9306..a0c2d104 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/MacroBlockDeclaration.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/MacroBlockDeclaration.cs
@@ -12,7 +12,10 @@ public static LNode Parse(TokenIterator iterator, Parser parser)
foreach (var p in parser.StatementParsePoints)
{
- if (pp.ContainsKey(p.Key)) continue;
+ if (pp.ContainsKey(p.Key))
+ {
+ continue;
+ }
pp.Add(p.Key, p.Value);
}
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/ParameterDeclaration.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/ParameterDeclaration.cs
index 48ceab47..4d55cd9f 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/ParameterDeclaration.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/ParameterDeclaration.cs
@@ -7,11 +7,16 @@ public sealed class ParameterDeclaration : IParsePoint
{
public static LNode Parse(TokenIterator iterator, Parser parser)
{
- Annotation.TryParse(parser, out var annotations);
+ _ = Annotation.TryParse(parser, out var annotations);
var keywordToken = iterator.Current;
var name = iterator.Match(TokenType.Identifier);
+ var assertNotNull = false;
+ if(iterator.ConsumeIfMatch(TokenType.Exclamation)) {
+ assertNotNull = true;
+ }
+
iterator.Match(TokenType.Colon);
var type = TypeLiteral.Parse(iterator, parser);
@@ -25,6 +30,10 @@ public static LNode Parse(TokenIterator iterator, Parser parser)
defaultValue = Expression.Parse(parser);
}
+ if(assertNotNull) {
+ annotations = annotations.Add(LNode.Id(Symbols.AssertNonNull));
+ }
+
return SyntaxTree.Factory.Var(type, name.Text, defaultValue).PlusAttrs(annotations)
.WithRange(keywordToken, iterator.Prev);
}
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/TypeMemberDeclaration.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/TypeMemberDeclaration.cs
index 13b074e6..e20d61f8 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/TypeMemberDeclaration.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Declarations/TypeMemberDeclaration.cs
@@ -7,8 +7,8 @@ public sealed class TypeMemberDeclaration : IParsePoint
{
public static LNode Parse(TokenIterator iterator, Parser parser)
{
- Annotation.TryParse(parser, out var annotations);
- Modifier.TryParse(parser, out var modifiers);
+ _ = Annotation.TryParse(parser, out var annotations);
+ _ = Modifier.TryParse(parser, out var modifiers);
LNode declaration = LNode.Missing;
@@ -28,7 +28,7 @@ public static LNode Parse(TokenIterator iterator, Parser parser)
{
var range = new SourceRange(parser.Document, iterator.Current.Start, iterator.Current.Text.Length);
- parser.Messages.Add(Message.Error($"Expected Function, Property or Field-declaration for Type, but got {iterator.Current}", range));
+ parser.AddError(new(Core.ErrorID.UnexpecedTypeMember, iterator.Current.Text), range);
iterator.NextToken();
}
@@ -71,13 +71,12 @@ public static LNode ParseProperty(TokenIterator iterator, Parser parser)
LNode setter = LNode.Missing;
var needModifier = false;
- LNodeList modifier;
- Modifier.TryParse(parser, out modifier);
+ _ = Modifier.TryParse(parser, out var modifier);
if (iterator.IsMatch(TokenType.Get))
{
iterator.NextToken();
- LNodeList args = LNode.List();
+ var args = LNode.List();
if (iterator.IsMatch(TokenType.Semicolon))
{
iterator.NextToken();
@@ -90,11 +89,15 @@ public static LNode ParseProperty(TokenIterator iterator, Parser parser)
needModifier = true;
}
- if (needModifier) Modifier.TryParse(parser, out modifier);
+ if (needModifier)
+ {
+ _ = Modifier.TryParse(parser, out modifier);
+ }
+
if (iterator.IsMatch(TokenType.Set))
{
iterator.NextToken();
- LNodeList args = LNode.List();
+ var args = LNode.List();
if (iterator.IsMatch(TokenType.Semicolon))
{
iterator.NextToken();
@@ -108,7 +111,7 @@ public static LNode ParseProperty(TokenIterator iterator, Parser parser)
else if (iterator.IsMatch(TokenType.Init))
{
iterator.NextToken();
- LNodeList args = LNode.List();
+ var args = LNode.List();
if (iterator.IsMatch(TokenType.Semicolon))
{
iterator.NextToken();
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/DocComment.cs b/Source/Backlang.Codeanalysis/Parsing/AST/DocComment.cs
new file mode 100644
index 00000000..3896ed9e
--- /dev/null
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/DocComment.cs
@@ -0,0 +1,26 @@
+using Loyc;
+using Loyc.Syntax;
+using System.Xml;
+
+namespace Backlang.Codeanalysis.Parsing.AST;
+
+public sealed class DocComment
+{
+ public static LNode Parse(Parser parser)
+ {
+ var comment = parser.Iterator.Match(TokenType.DocComment);
+ var xmlDocument = new XmlDocument();
+ xmlDocument.LoadXml($"{comment.Text}");
+
+ return LNode.Trivia(Symbol.For("DocComment"), xmlDocument);
+ }
+
+ public static bool TryParse(Parser parser, out LNode node)
+ {
+ var result = parser.Iterator.IsMatch(TokenType.DocComment);
+
+ node = result ? Parse(parser) : LNode.Missing;
+
+ return result;
+ }
+}
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Modifier.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Modifier.cs
index 226868d7..57fd4c39 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Modifier.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Modifier.cs
@@ -1,4 +1,5 @@
-using Loyc;
+using Backlang.Codeanalysis.Core;
+using Loyc;
using Loyc.Syntax;
using System.Collections.Immutable;
@@ -6,7 +7,7 @@ namespace Backlang.Codeanalysis.Parsing.AST;
public sealed class Modifier
{
- private static ImmutableDictionary possibleModifiers = new Dictionary() {
+ private static readonly ImmutableDictionary _possibleModifiers = new Dictionary() {
{ TokenType.Static, CodeSymbols.Static },
{ TokenType.Public, CodeSymbols.Public },
{ TokenType.Protected, CodeSymbols.Protected },
@@ -22,12 +23,12 @@ public static bool TryParse(Parser parser, out LNodeList node)
{
var modifiers = new LNodeList();
- while (possibleModifiers.ContainsKey(parser.Iterator.Current.Type))
+ while (_possibleModifiers.ContainsKey(parser.Iterator.Current.Type))
{
- var modifier = ParseSingle(parser.Iterator, parser);
+ var modifier = ParseSingle(parser.Iterator);
if (modifiers.Contains(modifier))
{
- parser.AddError($"Modifier '{modifier.Name.Name}' is already applied");
+ parser.AddError(new(ErrorID.DuplicateModifier, modifier.Name.Name), modifier.Range);
continue;
}
@@ -38,10 +39,10 @@ public static bool TryParse(Parser parser, out LNodeList node)
return modifiers.Count > 0;
}
- private static LNode ParseSingle(TokenIterator iterator, Parser parser)
+ private static LNode ParseSingle(TokenIterator iterator)
{
var currentToken = iterator.Current;
- var mod = SyntaxTree.Factory.Id(possibleModifiers[currentToken.Type]);
+ var mod = SyntaxTree.Factory.Id(_possibleModifiers[currentToken.Type]);
iterator.NextToken();
return mod.WithRange(currentToken);
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Signature.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Signature.cs
index b19c0c1b..a020ff25 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Signature.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Signature.cs
@@ -9,23 +9,19 @@ public static LNode Parse(Parser parser)
{
var iterator = parser.Iterator;
- LNode name;
- if (!TypeLiteral.TryParse(parser, out name))
+ if (!TypeLiteral.TryParse(parser, out var name))
{
- //error
var range = new SourceRange(parser.Document, iterator.Current.Start, iterator.Current.Text.Length);
- parser.Messages.Add(Message.Error(
- $"Expected Identifier, got {iterator.Current.Text}", range));
- }
- LNode returnType = SyntaxTree.Type("none", LNode.List());
- LNodeList generics = new();
+ parser.AddError(new(Core.ErrorID.ExpectedTypeLiteral, iterator.Current.Text), range);
+ }
+ LNode returnType = LNode.Missing;
iterator.Match(TokenType.OpenParen);
var parameters = ParameterDeclaration.ParseList(parser);
-
+ LNodeList generics = new();
while (iterator.IsMatch(TokenType.Where))
{
iterator.NextToken();
@@ -34,7 +30,11 @@ public static LNode Parse(Parser parser)
var bases = new LNodeList();
do
{
- if (iterator.IsMatch(TokenType.Comma)) iterator.NextToken();
+ if (iterator.IsMatch(TokenType.Comma))
+ {
+ iterator.NextToken();
+ }
+
bases.Add(TypeLiteral.Parse(iterator, parser));
} while (iterator.IsMatch(TokenType.Comma));
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/ContinueStatement.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/ContinueStatement.cs
similarity index 84%
rename from Source/Backlang.Codeanalysis/Parsing/AST/Statements/ContinueStatement.cs
rename to Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/ContinueStatement.cs
index 5fd7d1fd..02bff3ba 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/ContinueStatement.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/ContinueStatement.cs
@@ -1,6 +1,6 @@
using Loyc.Syntax;
-namespace Backlang.Codeanalysis.Parsing.AST.Statements;
+namespace Backlang.Codeanalysis.Parsing.AST.Statements.Loops;
public sealed class ContinueStatement : IParsePoint
{
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/DoWhileStatement.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/DoWhileStatement.cs
new file mode 100644
index 00000000..394b9078
--- /dev/null
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/DoWhileStatement.cs
@@ -0,0 +1,21 @@
+using Loyc.Syntax;
+
+namespace Backlang.Codeanalysis.Parsing.AST.Statements.Loops;
+
+public sealed class DoWhileStatement : IParsePoint
+{
+ public static LNode Parse(TokenIterator iterator, Parser parser)
+ {
+ var keywordToken = iterator.Prev;
+
+ var body = Statement.ParseBlock(parser);
+
+ iterator.Match(TokenType.While);
+
+ var cond = Expression.Parse(parser);
+
+ iterator.Match(TokenType.Semicolon);
+
+ return SyntaxTree.DoWhile(body, cond).WithRange(keywordToken, iterator.Prev);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/ForStatement.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/ForStatement.cs
similarity index 92%
rename from Source/Backlang.Codeanalysis/Parsing/AST/Statements/ForStatement.cs
rename to Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/ForStatement.cs
index 80012272..5a246b2c 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/ForStatement.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/ForStatement.cs
@@ -1,6 +1,6 @@
using Loyc.Syntax;
-namespace Backlang.Codeanalysis.Parsing.AST.Statements;
+namespace Backlang.Codeanalysis.Parsing.AST.Statements.Loops;
public sealed class ForStatement : IParsePoint
{
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/WhileStatement.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/WhileStatement.cs
similarity index 81%
rename from Source/Backlang.Codeanalysis/Parsing/AST/Statements/WhileStatement.cs
rename to Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/WhileStatement.cs
index 0a8f33ba..af52d52d 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/WhileStatement.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/Loops/WhileStatement.cs
@@ -1,12 +1,11 @@
using Loyc.Syntax;
-namespace Backlang.Codeanalysis.Parsing.AST.Statements;
+namespace Backlang.Codeanalysis.Parsing.AST.Statements.Loops;
public sealed class WhileStatement : IParsePoint
{
public static LNode Parse(TokenIterator iterator, Parser parser)
{
- // while true { 42; }
var keywordToken = iterator.Prev;
var cond = Expression.Parse(parser);
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/SwitchStatement.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/SwitchStatement.cs
index d64d6b8d..0fbd2751 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/SwitchStatement.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/SwitchStatement.cs
@@ -28,23 +28,34 @@ public static LNode Parse(TokenIterator iterator, Parser parser)
while (!parser.Iterator.IsMatch(TokenType.CloseCurly))
{
- bool autoBreak = iterator.IsMatch(TokenType.Break);
+ var autoBreak = iterator.IsMatch(TokenType.Break);
- if (autoBreak) iterator.Match(TokenType.Break);
+ if (autoBreak)
+ {
+ iterator.Match(TokenType.Break);
+ }
if (iterator.IsMatch(TokenType.Case))
+ {
cases.Add(ParseCase(parser, autoBreak));
+ }
else if (iterator.IsMatch(TokenType.If))
+ {
cases.Add(ParseIf(parser, autoBreak));
+ }
else if (iterator.IsMatch(TokenType.When))
+ {
cases.Add(ParseWhen(parser, autoBreak));
+ }
else if (iterator.IsMatch(TokenType.Default))
+ {
cases.Add(ParseDefault(parser, autoBreak));
+ }
else
{
var range = new SourceRange(parser.Document, iterator.Current.Start, iterator.Current.Text.Length);
- parser.Messages.Add(Message.Error("Switch Statement can only have case, if or default, but got " + iterator.Current.Text, range));
+ parser.AddError(new(Core.ErrorID.UnknownSwitchOption), range);
return LNode.Missing;
}
}
@@ -65,7 +76,9 @@ private static LNode ParseCase(Parser parser, bool autoBreak)
var body = Statement.ParseOneOrBlock(parser);
if (autoBreak)
+ {
body = body.PlusArg(LNode.Call(CodeSymbols.Break));
+ }
return SyntaxTree.Case(condition, body).WithRange(keywordToken, parser.Iterator.Prev);
}
@@ -79,7 +92,9 @@ private static LNode ParseDefault(Parser parser, bool autoBreak)
var body = Statement.ParseOneOrBlock(parser);
if (autoBreak)
+ {
body = body.PlusArg(LNode.Call(CodeSymbols.Break));
+ }
return SyntaxTree.Case(LNode.Call(CodeSymbols.Default), body);
}
@@ -95,7 +110,9 @@ private static LNode ParseIf(Parser parser, bool autoBreak)
var body = Statement.ParseOneOrBlock(parser);
if (autoBreak)
+ {
body = body.PlusArg(LNode.Call(CodeSymbols.Break));
+ }
return SyntaxTree.If(condition, body, SyntaxTree.Factory.Braces());
}
@@ -105,8 +122,7 @@ private static LNode ParseWhen(Parser parser, bool autoBreak)
parser.Iterator.Match(TokenType.When);
LNode binOp = LNode.Missing;
- LNode right = LNode.Missing;
-
+ LNode right;
if (Expression.GetBinaryOperatorPrecedence(parser.Iterator.Current.Type) > 0)
{
// with binary expression
@@ -122,7 +138,8 @@ private static LNode ParseWhen(Parser parser, bool autoBreak)
{
var range = new SourceRange(parser.Document, parser.Iterator.Current.Start, parser.Iterator.Current.Text.Length);
- parser.Messages.Add(Message.Error($"Expected {TokenType.Identifier} but got {parser.Iterator.Current.Type}", range));
+ parser.AddError(new(Core.ErrorID.ExpectedIdentifier, parser.Iterator.Current.Text), range);
+
return LNode.Missing;
}
var name = LNode.Id(parser.Iterator.Current.Text);
@@ -138,7 +155,9 @@ private static LNode ParseWhen(Parser parser, bool autoBreak)
var body = Statement.ParseOneOrBlock(parser);
if (autoBreak)
+ {
body = body.PlusArg(LNode.Call(CodeSymbols.Break));
+ }
return SyntaxTree.When(binOp, right, body);
}
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/TryStatement.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/TryStatement.cs
index e9c49fda..0081b8a3 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Statements/TryStatement.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Statements/TryStatement.cs
@@ -6,7 +6,6 @@ public sealed class TryStatement : IParsePoint
{
public static LNode Parse(TokenIterator iterator, Parser parser)
{
- // try {} catch (Exception e) {} catch (Exception e) {} finally {}
var keywordToken = iterator.Prev;
var body = Statement.ParseOneOrBlock(parser);
LNodeList catches = new(LNode.Missing);
@@ -15,7 +14,7 @@ public static LNode Parse(TokenIterator iterator, Parser parser)
{
var range = new SourceRange(parser.Document, iterator.Current.Start, iterator.Current.Text.Length);
- parser.Messages.Add(Message.Error("Expected at least one catch block at try statement", range));
+ parser.AddError(new(Core.ErrorID.NoCatchBlock), range);
}
while (iterator.Current.Type == TokenType.Catch)
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/Symbols.cs b/Source/Backlang.Codeanalysis/Parsing/AST/Symbols.cs
index 2405e16c..d64a70b0 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/Symbols.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/Symbols.cs
@@ -22,6 +22,7 @@ public static class Symbols
public static readonly Symbol Mutable = GSymbol.Get("#mutable");
public static readonly Symbol PointerType = GSymbol.Get("#type*");
public static readonly Symbol RefType = GSymbol.Get("#type&");
+ public static readonly Symbol NullableType = GSymbol.Get("#type?");
public static readonly Symbol Range = GSymbol.Get("'..");
public static readonly Symbol ToExpand = GSymbol.Get("'to_expand'");
public static readonly Symbol TypeLiteral = GSymbol.Get("#type");
@@ -30,4 +31,5 @@ public static class Symbols
public static readonly Symbol Init = GSymbol.Get("#init");
public static readonly Symbol Unit = GSymbol.Get("#unit");
public static readonly Symbol UnitDecl = GSymbol.Get("#unitDecl");
+ public static readonly Symbol AssertNonNull = GSymbol.Get("#notnull");
}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Parsing/AST/TypeLiteral.cs b/Source/Backlang.Codeanalysis/Parsing/AST/TypeLiteral.cs
index eafa36e2..fa63d02d 100644
--- a/Source/Backlang.Codeanalysis/Parsing/AST/TypeLiteral.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/AST/TypeLiteral.cs
@@ -1,4 +1,5 @@
-using Loyc.Syntax;
+using Backlang.Codeanalysis.Core;
+using Loyc.Syntax;
namespace Backlang.Codeanalysis.Parsing.AST;
@@ -28,84 +29,32 @@ public static LNode Parse(TokenIterator iterator, Parser parser)
typeNode = SyntaxTree.RefType(typeNode).WithRange(typeToken, iterator.Prev);
}
- else if (iterator.IsMatch(TokenType.OpenSquare))
- {
+ else if(iterator.IsMatch(TokenType.Questionmark)) {
iterator.NextToken();
- var dimensions = 1;
-
- while (iterator.IsMatch(TokenType.Comma))
- {
- dimensions++;
-
- iterator.NextToken();
- }
-
- iterator.Match(TokenType.CloseSquare);
-
- typeNode = SyntaxTree.Array(typeNode, dimensions).WithRange(typeToken, iterator.Prev);
+ typeNode = SyntaxTree.NullableType(typeNode).WithRange(typeToken, iterator.Prev);
+ }
+ else if (iterator.IsMatch(TokenType.OpenSquare))
+ {
+ typeNode = ParseArrayType(iterator, typeNode, typeToken);
}
else if (iterator.IsMatch(TokenType.LessThan))
{
- iterator.NextToken();
-
- while (!iterator.IsMatch(TokenType.GreaterThan))
- {
- if (iterator.IsMatch(TokenType.Identifier))
- {
- args.Add(Parse(iterator, parser));
- }
-
- if (!iterator.IsMatch(TokenType.GreaterThan))
- {
- iterator.Match(TokenType.Comma);
- }
- }
-
- iterator.Match(TokenType.GreaterThan);
-
- typeNode = SyntaxTree.Type(typename, args).WithRange(typeToken, parser.Iterator.Prev);
+ typeNode = ParseGenericType(iterator, parser, typeToken, typename, args);
}
}
else if (iterator.IsMatch(TokenType.None))
{
- typeNode = SyntaxTree.Type("none", LNode.List()).WithRange(typeToken); // Missing is the normal type for none
+ typeNode = SyntaxTree.Type("none", LNode.List()).WithRange(typeToken);
iterator.NextToken();
}
else if (iterator.IsMatch(TokenType.OpenParen))
{
- iterator.Match(TokenType.OpenParen);
-
- var parameters = new LNodeList();
- while (parser.Iterator.Current.Type != TokenType.CloseParen)
- {
- parameters.Add(TypeLiteral.Parse(iterator, parser));
-
- if (parser.Iterator.Current.Type != TokenType.CloseParen)
- {
- parser.Iterator.Match(TokenType.Comma);
- }
- }
-
- parser.Iterator.Match(TokenType.CloseParen);
-
- if (iterator.Current.Type == TokenType.Arrow)
- {
- iterator.NextToken();
-
- var returnType = TypeLiteral.Parse(iterator, parser);
-
- typeNode = SyntaxTree.Factory.Call(CodeSymbols.Fn,
- LNode.List(returnType, LNode.Missing, LNode.Call(CodeSymbols.AltList, parameters))).WithRange(typeToken, iterator.Prev);
- }
- else
- {
- typeNode = SyntaxTree.Factory.Tuple(parameters).WithRange(typeToken, iterator.Prev);
- }
+ typeNode = ParseFunctionOrTupleType(iterator, parser, typeToken);
}
else
{
- parser.AddError("Expected Identifier, TupleType or Function-Signature as TypeLiteral, but got " + iterator.Current.Type);
+ parser.AddError(new(ErrorID.UnexpecedType, TokenIterator.GetTokenRepresentation(iterator.Current.Type))); //ToDo: Add Range
typeNode = LNode.Missing;
iterator.NextToken();
@@ -127,4 +76,82 @@ public static bool TryParse(Parser parser, out LNode node)
return true;
}
+
+ private static LNode ParseFunctionOrTupleType(TokenIterator iterator, Parser parser, Token typeToken)
+ {
+ LNode typeNode;
+ iterator.Match(TokenType.OpenParen);
+
+ var parameters = new LNodeList();
+ while (parser.Iterator.Current.Type != TokenType.CloseParen)
+ {
+ parameters.Add(TypeLiteral.Parse(iterator, parser));
+
+ if (parser.Iterator.Current.Type != TokenType.CloseParen)
+ {
+ parser.Iterator.Match(TokenType.Comma);
+ }
+ }
+
+ parser.Iterator.Match(TokenType.CloseParen);
+
+ if (iterator.Current.Type == TokenType.Arrow)
+ {
+ iterator.NextToken();
+
+ var returnType = Parse(iterator, parser);
+
+ typeNode = SyntaxTree.Factory.Call(CodeSymbols.Fn,
+ LNode.List(returnType, LNode.Missing, LNode.Call(CodeSymbols.AltList, parameters))).WithRange(typeToken, iterator.Prev);
+ }
+ else
+ {
+ typeNode = SyntaxTree.Factory.Tuple(parameters).WithRange(typeToken, iterator.Prev);
+ }
+
+ return typeNode;
+ }
+
+ private static LNode ParseGenericType(TokenIterator iterator, Parser parser, Token typeToken, string typename, LNodeList args)
+ {
+ LNode typeNode;
+ iterator.NextToken();
+
+ while (!iterator.IsMatch(TokenType.GreaterThan))
+ {
+ if (iterator.IsMatch(TokenType.Identifier))
+ {
+ args.Add(Parse(iterator, parser));
+ }
+
+ if (!iterator.IsMatch(TokenType.GreaterThan))
+ {
+ iterator.Match(TokenType.Comma);
+ }
+ }
+
+ iterator.Match(TokenType.GreaterThan);
+
+ typeNode = SyntaxTree.Type(typename, args).WithRange(typeToken, parser.Iterator.Prev);
+ return typeNode;
+ }
+
+ private static LNode ParseArrayType(TokenIterator iterator, LNode typeNode, Token typeToken)
+ {
+ iterator.NextToken();
+
+ var dimensions = 1;
+
+ while (iterator.IsMatch(TokenType.Comma))
+ {
+ dimensions++;
+
+ iterator.NextToken();
+ }
+
+ iterator.Match(TokenType.CloseSquare);
+
+ typeNode = SyntaxTree.Array(typeNode, dimensions).WithRange(typeToken, iterator.Prev);
+ return typeNode;
+ }
}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Parsing/Expression.cs b/Source/Backlang.Codeanalysis/Parsing/Expression.cs
index f4d044e3..3203e117 100644
--- a/Source/Backlang.Codeanalysis/Parsing/Expression.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/Expression.cs
@@ -48,26 +48,35 @@ static Expression()
public static LNode Parse(Parser parser, ParsePoints parsePoints = null, int parentPrecedence = 0)
{
- LNode left;
- var unaryOperatorPrecedence = GetPreUnaryOperatorPrecedence(parser.Iterator.Current.Type);
+ LNode left = null;
+ var preUnaryOperatorPrecedence = GetPreUnaryOperatorPrecedence(parser.Iterator.Current.Type);
- if (unaryOperatorPrecedence != 0 && unaryOperatorPrecedence >= parentPrecedence)
+ if (preUnaryOperatorPrecedence != 0 && preUnaryOperatorPrecedence >= parentPrecedence)
{
- var operatorToken = parser.Iterator.NextToken();
+ if (IsPreUnary(parser.Iterator.Current.Type))
+ {
+ var operatorToken = parser.Iterator.NextToken();
- var operand = Parse(parser, parsePoints, unaryOperatorPrecedence + 1);
+ var operand = Parse(parser, parsePoints, preUnaryOperatorPrecedence + 1);
- left = SyntaxTree.Unary(GSymbol.Get($"'{operatorToken.Text}"), operand).WithRange(operatorToken.Start, operand.Range.EndIndex).WithStyle(NodeStyle.PrefixNotation);
+ left = SyntaxTree.Unary(GSymbol.Get($"'{operatorToken.Text}"), operand).WithRange(operatorToken.Start, operand.Range.EndIndex).WithStyle(NodeStyle.PrefixNotation);
+ }
}
else
{
- left = parser.ParsePrimary(parsePoints);
+ left = parser.ParsePrimary();
- if (IsPostUnary(parser.Iterator.Current.Type))
+ //parsing postunarys for: hello?;
+ var postUnaryOperatorPrecedence = GetPostUnaryOperatorPrecedence(parser.Iterator.Current.Type);
+
+ if (postUnaryOperatorPrecedence != 0 && postUnaryOperatorPrecedence >= parentPrecedence)
{
- var operatorToken = parser.Iterator.NextToken();
+ if (IsPostUnary(parser.Iterator.Current.Type))
+ {
+ var unaryOperatorToken = parser.Iterator.NextToken();
- left = SyntaxTree.Unary(GSymbol.Get($"'{operatorToken.Text}"), left).WithRange(left.Range.StartIndex, operatorToken.End);
+ left = SyntaxTree.Unary(GSymbol.Get($"'suf{unaryOperatorToken.Text}"), left).WithRange(left.Range.StartIndex, unaryOperatorToken.End).WithStyle(NodeStyle.Operator);
+ }
}
}
@@ -83,6 +92,19 @@ public static LNode Parse(Parser parser, ParsePoints parsePoints = null, int par
var right = Parse(parser, parsePoints, precedence);
left = SyntaxTree.Binary(GSymbol.Get($"'{operatorToken.Text}"), left, right).WithRange(left.Range.StartIndex, right.Range.StartIndex);
+
+ // parsing postunary for: Hello::new()? = false;
+ var postUnaryOperatorPrecedence = GetPostUnaryOperatorPrecedence(parser.Iterator.Current.Type);
+
+ if (postUnaryOperatorPrecedence != 0 && postUnaryOperatorPrecedence >= parentPrecedence)
+ {
+ if (IsPostUnary(parser.Iterator.Current.Type))
+ {
+ var unaryOperatorToken = parser.Iterator.NextToken();
+
+ left = SyntaxTree.Unary(GSymbol.Get($"'suf{unaryOperatorToken.Text}"), left).WithRange(left.Range.StartIndex, unaryOperatorToken.End).WithStyle(NodeStyle.Operator);
+ }
+ }
}
return left;
@@ -94,7 +116,9 @@ public static LNodeList ParseList(Parser parser, TokenType terminator, bool cons
}
private static int GetPreUnaryOperatorPrecedence(TokenType kind) => PreUnaryOperators.GetValueOrDefault(kind);
+ private static int GetPostUnaryOperatorPrecedence(TokenType kind) => PostUnaryOperators.GetValueOrDefault(kind);
+ private static bool IsPreUnary(TokenType kind) => PreUnaryOperators.ContainsKey(kind);
private static bool IsPostUnary(TokenType kind) => PostUnaryOperators.ContainsKey(kind);
private class ExpressionParser : IParsePoint
diff --git a/Source/Backlang.Codeanalysis/Parsing/LNodeExtensions.cs b/Source/Backlang.Codeanalysis/Parsing/LNodeExtensions.cs
index a511e8fa..cadc13a9 100644
--- a/Source/Backlang.Codeanalysis/Parsing/LNodeExtensions.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/LNodeExtensions.cs
@@ -1,4 +1,5 @@
using Loyc.Syntax;
+using Backlang.Codeanalysis.Parsing.AST;
namespace Backlang.Codeanalysis.Parsing;
@@ -23,4 +24,9 @@ public static LNode FromToken(this LNodeFactory factory, Token token)
{
return factory.Id(token.Text).WithRange(token);
}
+
+ public static bool IsNoneType(this LNode node)
+ {
+ return node.Name == Symbols.TypeLiteral && node.Args[0].Args[0].Name.Name == "none" && node.Args[0].Args[0].IsId;
+ }
}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Parsing/Lexer.cs b/Source/Backlang.Codeanalysis/Parsing/Lexer.cs
index 72e80ce4..9a3d68a2 100644
--- a/Source/Backlang.Codeanalysis/Parsing/Lexer.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/Lexer.cs
@@ -1,7 +1,10 @@
using Backlang.Codeanalysis.Core;
using Backlang.Codeanalysis.Core.Attributes;
+using Loyc.Collections.Impl;
using Loyc.Syntax;
using System.Reflection;
+using System.Text;
+using System.Transactions;
namespace Backlang.Codeanalysis.Parsing;
@@ -32,6 +35,11 @@ static Lexer()
protected override Token NextToken()
{
+ if (IsMatch("///"))
+ {
+ return LexDocComment();
+ }
+
SkipWhitespaces();
SkipComments();
@@ -87,6 +95,36 @@ protected override Token NextToken()
return Token.Invalid;
}
+ private Token LexDocComment()
+ {
+ var oldPos = _position;
+ var contentBuilder = new StringBuilder();
+
+ do
+ {
+ contentBuilder.AppendLine(ReadLine().TrimStart('/').Trim());
+ } while (IsMatch("///"));
+
+ return new Token(TokenType.DocComment, contentBuilder.ToString(), oldPos, _position, _line, _column);
+ }
+
+
+ private string ReadLine()
+ {
+ var sb = new StringBuilder();
+
+ while (Current() != '\n')
+ {
+ Advance();
+ _column++;
+ }
+ Advance();
+ _column = 0;
+ _line++;
+
+ return sb.ToString();
+ }
+
private static bool IsBinaryDigit(char c)
{
return c == '0' || c == '1';
@@ -94,7 +132,7 @@ private static bool IsBinaryDigit(char c)
private static bool IsHex(char c)
{
- return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F';
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
private TokenType GetOperatorKind(Token identifier)
@@ -165,7 +203,7 @@ private Token LexCharLiteral()
if (Current() == '\n' || Current() == '\r')
{
var range = new SourceRange(_document, _column, 1);
- Messages.Add(Message.Error($"Unterminated CharLiteral", range));
+ Messages.Add(Message.Error(ErrorID.UnterminatedCharLiteral, range));
return Token.Invalid;
}
@@ -216,8 +254,10 @@ private Token LexDoubleQuoteString()
{
if (Current() == '\n' || Current() == '\r')
{
- var range = new SourceRange(_document, _column, 1);
- Messages.Add(Message.Error($"Unterminated String", range));
+ var range = new SourceRange(_document, _position, 1);
+ Messages.Add(Message.Error(ErrorID.UnterminatedStringLiteral, range));
+
+ return new Token(TokenType.StringLiteral, _document.Text.Slice(oldpos, _position - oldpos - 1).ToString(), oldpos - 1, _position, _line, oldColumn);
}
Advance();
@@ -301,7 +341,7 @@ private void SkipComments()
}
else if (IsMatch("/*"))
{
- int oldcol = _column;
+ int oldpos = _position;
Advance();
Advance();
@@ -328,8 +368,9 @@ private void SkipComments()
}
else
{
- var range = new SourceRange(_document, _column, 1);
- Messages.Add(Message.Error("Multiline comment is not closed.", range));
+ var range = new SourceRange(_document, oldpos, _position);
+ Messages.Add(Message.Error(ErrorID.NotClosedMultilineComment, range));
+
return;
}
diff --git a/Source/Backlang.Codeanalysis/Parsing/Message.cs b/Source/Backlang.Codeanalysis/Parsing/Message.cs
index a8b47fee..4d6621da 100644
--- a/Source/Backlang.Codeanalysis/Parsing/Message.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/Message.cs
@@ -1,4 +1,5 @@
-using Loyc.Syntax;
+using Backlang.Codeanalysis.Core;
+using Loyc.Syntax;
namespace Backlang.Codeanalysis.Parsing;
@@ -28,14 +29,14 @@ public Message(MessageSeverity severity, string text, SourceRange range)
public MessageSeverity Severity { get; set; }
public string Text { get; set; }
- public static Message Error(string message, SourceRange range)
+ public static Message Error(LocalizableString message, SourceRange range)
{
return new Message(MessageSeverity.Error, message, range);
}
- public static Message Error(string message)
+ public static Message Error(LocalizableString message)
{
- return Error(message, SourceRange.Synthetic);
+ return new Message(MessageSeverity.Error, message, SourceRange.Synthetic);
}
public static Message Info(string message, SourceRange range)
diff --git a/Source/Backlang.Codeanalysis/Parsing/Parser.Expressions.cs b/Source/Backlang.Codeanalysis/Parsing/Parser.Expressions.cs
index 5398f47d..dba73acb 100644
--- a/Source/Backlang.Codeanalysis/Parsing/Parser.Expressions.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/Parser.Expressions.cs
@@ -8,7 +8,7 @@ namespace Backlang.Codeanalysis.Parsing;
public sealed partial class Parser
{
- private Dictionary _lits = new() {
+ private readonly Dictionary _lits = new() {
{"ub", CodeSymbols.UInt8},
{"us", CodeSymbols.UInt16},
{"u", CodeSymbols.UInt32},
@@ -22,22 +22,19 @@ public sealed partial class Parser
{"d", Symbols.Float64},
};
- public void AddError(string message, SourceRange range)
+ public void AddError(LocalizableString message, SourceRange range)
{
Messages.Add(Message.Error(message, range));
}
- public void AddError(string message)
+ public void AddError(LocalizableString message)
{
Messages.Add(Message.Error(message, new SourceRange(Document, Iterator.Current.Start, Iterator.Current.Text.Length)));
}
internal LNode ParsePrimary(ParsePoints parsePoints = null)
{
- if (parsePoints == null)
- {
- parsePoints = ExpressionParsePoints;
- }
+ parsePoints ??= ExpressionParsePoints;
return Iterator.Current.Type switch
{
@@ -63,7 +60,7 @@ private LNode ParseArrayLiteral()
return SyntaxTree.Factory.Call(CodeSymbols.Array, elements).WithRange(startToken, Iterator.Prev);
}
- private LNode Invalid(string message)
+ private LNode Invalid(LocalizableString message)
{
AddError(message);
@@ -75,15 +72,19 @@ private LNode InvokeExpressionParsePoint(ParsePoints parsePoints)
var token = Iterator.Current;
var type = token.Type;
- if (parsePoints.ContainsKey(type))
+ if (parsePoints.TryGetValue(type, out var value))
{
Iterator.NextToken();
- return parsePoints[type](Iterator, this).WithRange(token, Iterator.Prev);
+ return value(Iterator, this).WithRange(token, Iterator.Prev);
+ }
+ else if (type == Token.Invalid.Type)
+ {
+ return LNode.Missing;
}
else
{
- return Invalid($"Unexpected Expression '{Iterator.Current.Text}'");
+ return Invalid(ErrorID.UnknownExpression);
}
}
@@ -131,7 +132,7 @@ private LNode ParseHexNumber()
}
return SyntaxTree.Factory.Call(CodeSymbols.Int32,
- LNode.List(SyntaxTree.Factory.Literal(int.Parse(valueToken.Text, NumberStyles.HexNumber))))
+ LNode.List(SyntaxTree.Factory.Literal(result)))
.WithRange(Iterator.Prev);
}
@@ -162,14 +163,14 @@ private LNode ParseNumber()
if (Iterator.Current.Type == TokenType.Identifier)
{
- if (_lits.ContainsKey(Iterator.Current.Text.ToLower()))
+ if (_lits.TryGetValue(Iterator.Current.Text.ToLower(), out var value))
{
- result = SyntaxTree.Factory.Call(_lits[Iterator.Current.Text.ToLower()],
+ result = SyntaxTree.Factory.Call(value,
LNode.List(result)).WithRange(Iterator.Prev, Iterator.Current);
}
else
{
- AddError($"Unknown Literal {Iterator.Current.Text}");
+ AddError(new(ErrorID.UnknownLiteral, Iterator.Current.Text));
result = LNode.Missing;
}
diff --git a/Source/Backlang.Codeanalysis/Parsing/Parser.ParsePoints.cs b/Source/Backlang.Codeanalysis/Parsing/Parser.ParsePoints.cs
index 4868b885..3176612f 100644
--- a/Source/Backlang.Codeanalysis/Parsing/Parser.ParsePoints.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/Parser.ParsePoints.cs
@@ -1,8 +1,10 @@
-using Backlang.Codeanalysis.Parsing.AST;
+using Backlang.Codeanalysis.Core;
+using Backlang.Codeanalysis.Parsing.AST;
using Backlang.Codeanalysis.Parsing.AST.Declarations;
using Backlang.Codeanalysis.Parsing.AST.Expressions;
using Backlang.Codeanalysis.Parsing.AST.Expressions.Match;
using Backlang.Codeanalysis.Parsing.AST.Statements;
+using Backlang.Codeanalysis.Parsing.AST.Statements.Loops;
using Loyc.Syntax;
namespace Backlang.Codeanalysis.Parsing;
@@ -50,6 +52,7 @@ public void InitParsePoints()
AddStatementParsePoint(TokenType.Switch);
AddStatementParsePoint(TokenType.If);
AddStatementParsePoint(TokenType.While);
+ AddStatementParsePoint(TokenType.Do);
AddStatementParsePoint(TokenType.Try);
AddStatementParsePoint(TokenType.For);
AddStatementParsePoint(TokenType.Identifier);
@@ -80,10 +83,11 @@ public LNodeList InvokeDeclarationParsePoints(TokenType terminator = TokenType.E
var body = new LNodeList();
while (Iterator.Current.Type != terminator)
{
+ DocComment.TryParse(this, out var docComment);
Annotation.TryParse(this, out var annotation);
Modifier.TryParse(this, out var modifiers);
- var item = InvokeParsePoint(parsePoints)?.PlusAttrs(annotation).PlusAttrs(modifiers);
+ var item = InvokeParsePoint(parsePoints)?.PlusAttrs(annotation).PlusAttrs(modifiers).PlusAttr(docComment);
if (item != null)
{
@@ -107,7 +111,7 @@ public LNode InvokeParsePoint(ParsePoints parsePoints)
var range = new SourceRange(Document, Iterator.Current.Start, Iterator.Current.Text.Length);
- Messages.Add(Message.Error($"Unexpected '{Iterator.Current.Text}'", range));
+ AddError(new(ErrorID.UnknownExpression, Iterator.Current.Text), range);
Iterator.NextToken();
diff --git a/Source/Backlang.Codeanalysis/Parsing/Parser.cs b/Source/Backlang.Codeanalysis/Parsing/Parser.cs
index a2016daa..e9bfbc5a 100644
--- a/Source/Backlang.Codeanalysis/Parsing/Parser.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/Parser.cs
@@ -1,3 +1,4 @@
+using Backlang.Codeanalysis.Core;
using Backlang.Codeanalysis.Parsing.AST;
using Loyc.Syntax;
@@ -29,7 +30,7 @@ public static CompilationUnit Parse(SourceDocument src)
return new CompilationUnit
{
Body = LNode.List(LNode.Missing),
- Messages = new() { Message.Error("Empty File", SourceRange.Synthetic) },
+ Messages = new() { Message.Error(ErrorID.EmptyFile, SourceRange.Synthetic) },
Document = document
};
}
diff --git a/Source/Backlang.Codeanalysis/Parsing/Precedences/BinaryOpPrecedences.cs b/Source/Backlang.Codeanalysis/Parsing/Precedences/BinaryOpPrecedences.cs
index d06485ad..65ecd4ce 100644
--- a/Source/Backlang.Codeanalysis/Parsing/Precedences/BinaryOpPrecedences.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/Precedences/BinaryOpPrecedences.cs
@@ -1,4 +1,5 @@
namespace Backlang.Codeanalysis.Parsing.Precedences;
+
public enum BinaryOpPrecedences
{
Casting = 1, // as
@@ -17,12 +18,12 @@ public enum BinaryOpPrecedences
Or = Percent,
Comparisons = Or, // < <= >= >
SwapOperator = 2,
-
+
FunctionCalls = 7, // . ::
PipeOperator = 8, // |>
- OperationShortcuts = 9, // += -= *= /=
+ Dot = 8,
+ OperationShortcuts = 2, // += -= *= /=
Equals = OperationShortcuts,
-
-}
+}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Parsing/SourceDocument.cs b/Source/Backlang.Codeanalysis/Parsing/SourceDocument.cs
index 3fb74e6e..a1997247 100644
--- a/Source/Backlang.Codeanalysis/Parsing/SourceDocument.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/SourceDocument.cs
@@ -5,7 +5,7 @@ namespace Backlang.Codeanalysis.Parsing;
public sealed class SourceDocument
{
- private SourceFile _document;
+ private readonly SourceFile _document;
public SourceDocument(string filename)
{
diff --git a/Source/Backlang.Codeanalysis/Parsing/SyntaxTree.cs b/Source/Backlang.Codeanalysis/Parsing/SyntaxTree.cs
index 052cf158..3bdd80a6 100644
--- a/Source/Backlang.Codeanalysis/Parsing/SyntaxTree.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/SyntaxTree.cs
@@ -168,6 +168,11 @@ public static LNode RefType(LNode type)
return Factory.Call(Symbols.RefType, LNode.List(type));
}
+ public static LNode NullableType(LNode type)
+ {
+ return Factory.Call(Symbols.NullableType, LNode.List(type));
+ }
+
public static LNode Signature(LNode name, LNode type, LNodeList args, LNodeList generics)
{
return Factory.Call(CodeSymbols.Fn, LNode.List(
@@ -249,8 +254,15 @@ public static LNode UnitDeclaration(Token nameToken)
return Factory.Call(Symbols.UnitDecl, LNode.List(Factory.FromToken(nameToken)));
}
- internal static LNode TypeOfExpression(LNode type)
+ public static LNode TypeOfExpression(LNode type)
{
return Factory.Call(CodeSymbols.Typeof, LNode.List(type));
}
+
+ public static LNode DoWhile(LNode body, LNode cond)
+ {
+ return Factory.Call(CodeSymbols.DoWhile, LNode.List(body, cond));
+ }
+
+
}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Parsing/TokenIterator.cs b/Source/Backlang.Codeanalysis/Parsing/TokenIterator.cs
index 835cf923..1d57db42 100644
--- a/Source/Backlang.Codeanalysis/Parsing/TokenIterator.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/TokenIterator.cs
@@ -72,7 +72,7 @@ public Token Match(TokenType kind)
return NextToken();
Messages.Add(
- Message.Error($"Expected '{GetTokenRepresentation(kind)}' but got '{GetTokenRepresentation(Current.Type)}'",
+ Message.Error(new(Core.ErrorID.Expected, GetTokenRepresentation(kind), GetTokenRepresentation(Current.Type)),
new SourceRange(_document, Current.Start, Current.Text.Length)));
NextToken();
diff --git a/Source/Backlang.Codeanalysis/Parsing/TokenType.cs b/Source/Backlang.Codeanalysis/Parsing/TokenType.cs
index f216ccd0..8cbc83db 100644
--- a/Source/Backlang.Codeanalysis/Parsing/TokenType.cs
+++ b/Source/Backlang.Codeanalysis/Parsing/TokenType.cs
@@ -15,7 +15,7 @@ public enum TokenType
CharLiteral,
[Lexeme(".")]
- [BinaryOperatorInfo(BinaryOpPrecedences.FunctionCalls)]
+ [BinaryOperatorInfo(BinaryOpPrecedences.Dot)]
Dot,
[Lexeme("::")]
@@ -62,6 +62,10 @@ public enum TokenType
[Lexeme("*")]
Star,
+ [PostUnaryOperatorInfo(UnaryOpPrecedences.Negate)]
+ [Lexeme(".*")]
+ DotAsterisk, // for namespace imports
+
[BinaryOperatorInfo(BinaryOpPrecedences.Hat)]
[Lexeme("**")]
StarStar,
@@ -91,6 +95,7 @@ public enum TokenType
[Lexeme("-=")]
[Lexeme("|=")]
[Lexeme("&=")]
+ [Lexeme("!!=")]
[BinaryOperatorInfo(BinaryOpPrecedences.OperationShortcuts)]
EqualsShortcutToken,
@@ -98,9 +103,6 @@ public enum TokenType
[BinaryOperatorInfo(BinaryOpPrecedences.Equals)]
EqualsToken,
- [Lexeme("#")]
- Hash,
-
[Lexeme("<=")]
[BinaryOperatorInfo(BinaryOpPrecedences.Comparisons)]
LessThanEqual,
@@ -149,6 +151,10 @@ public enum TokenType
[PreUnaryOperatorInfo(UnaryOpPrecedences.Dollar)]
Dollar,
+ [Lexeme("?")]
+ [PostUnaryOperatorInfo(UnaryOpPrecedences.Negate)]
+ Questionmark,
+
[Lexeme("==")]
[BinaryOperatorInfo(BinaryOpPrecedences.EqualsEquals)]
EqualsEquals,
@@ -291,6 +297,9 @@ public enum TokenType
[Keyword("while")]
While,
+ [Keyword("do")]
+ Do,
+
[Keyword("in")]
In,
@@ -353,4 +362,5 @@ public enum TokenType
[Keyword("unit")]
Unit,
+ DocComment,
}
\ No newline at end of file
diff --git a/Source/Backlang.Codeanalysis/Properties/Resources.Designer.cs b/Source/Backlang.Codeanalysis/Properties/Resources.Designer.cs
new file mode 100644
index 00000000..f11e57ec
--- /dev/null
+++ b/Source/Backlang.Codeanalysis/Properties/Resources.Designer.cs
@@ -0,0 +1,342 @@
+//------------------------------------------------------------------------------
+//
+// Dieser Code wurde von einem Tool generiert.
+// Laufzeitversion:4.0.30319.42000
+//
+// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+// der Code erneut generiert wird.
+//
+//------------------------------------------------------------------------------
+
+namespace Backlang.Codeanalysis.Properties {
+ using System;
+
+
+ ///
+ /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
+ ///
+ // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
+ // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
+ // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
+ // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Backlang.Codeanalysis.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
+ /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Expected Identifier, TupleType or Function-Signature as TypeLiteral, but got {0} ähnelt.
+ ///
+ internal static string BL_0001_ {
+ get {
+ return ResourceManager.GetString("BL(0001)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Invalid Modifier Combination ähnelt.
+ ///
+ internal static string BL_0002_ {
+ get {
+ return ResourceManager.GetString("BL(0002)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Unknown Character '{0}' ähnelt.
+ ///
+ internal static string BL_0003_ {
+ get {
+ return ResourceManager.GetString("BL(0003)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Unterminated Char-Literal ähnelt.
+ ///
+ internal static string BL_0004_ {
+ get {
+ return ResourceManager.GetString("BL(0004)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Unexpected Expression {0} ähnelt.
+ ///
+ internal static string BL_0005_ {
+ get {
+ return ResourceManager.GetString("BL(0005)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Unknown Literal {0} ähnelt.
+ ///
+ internal static string BL_0006_ {
+ get {
+ return ResourceManager.GetString("BL(0006)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Trailing comma is forbidden ähnelt.
+ ///
+ internal static string BL_0007_ {
+ get {
+ return ResourceManager.GetString("BL(0007)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Bitfield member declaration only allows literals ähnelt.
+ ///
+ internal static string BL_0008_ {
+ get {
+ return ResourceManager.GetString("BL(0008)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Expected Function, Property or Field-declaration for Type, but got {0} ähnelt.
+ ///
+ internal static string BL_0009_ {
+ get {
+ return ResourceManager.GetString("BL(0009)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Expected Type but got {0} ähnelt.
+ ///
+ internal static string BL_0010_ {
+ get {
+ return ResourceManager.GetString("BL(0010)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Unexpected Switch Option ähnelt.
+ ///
+ internal static string BL_0011_ {
+ get {
+ return ResourceManager.GetString("BL(0011)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Expected at least one catch block ähnelt.
+ ///
+ internal static string BL_0012_ {
+ get {
+ return ResourceManager.GetString("BL(0012)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die SourceFile is empty ähnelt.
+ ///
+ internal static string BL_0013_ {
+ get {
+ return ResourceManager.GetString("BL(0013)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Expected Identifier but got {0} ähnelt.
+ ///
+ internal static string BL_0014_ {
+ get {
+ return ResourceManager.GetString("BL(0014)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Unterminated String-Literal ähnelt.
+ ///
+ internal static string BL_0015_ {
+ get {
+ return ResourceManager.GetString("BL(0015)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Multiline comment is not closed ähnelt.
+ ///
+ internal static string BL_0016_ {
+ get {
+ return ResourceManager.GetString("BL(0016)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Expected '{0}' but got '{1}' ähnelt.
+ ///
+ internal static string BL_0017_ {
+ get {
+ return ResourceManager.GetString("BL(0017)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Duplicate Modifier '{0}' ähnelt.
+ ///
+ internal static string BL_0018_ {
+ get {
+ return ResourceManager.GetString("BL(0018)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Namespace '{0}' already imported ähnelt.
+ ///
+ internal static string BL_0019_ {
+ get {
+ return ResourceManager.GetString("BL(0019)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Got OutputType 'Exe' but couldn't find entry point. ähnelt.
+ ///
+ internal static string BL_0020_ {
+ get {
+ return ResourceManager.GetString("BL(0020)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die {0} cannot be found. Did you mean '{1}'? ähnelt.
+ ///
+ internal static string BL_0021_ {
+ get {
+ return ResourceManager.GetString("BL(0021)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Cannot implement '{0}', type not found ähnelt.
+ ///
+ internal static string BL_0022_ {
+ get {
+ return ResourceManager.GetString("BL(0022)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Cannot implement unit type '{0}' ähnelt.
+ ///
+ internal static string BL_0023_ {
+ get {
+ return ResourceManager.GetString("BL(0023)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die '{0}' already declared ähnelt.
+ ///
+ internal static string BL_0024_ {
+ get {
+ return ResourceManager.GetString("BL(0024)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Type mismatch {0} {1} ähnelt.
+ ///
+ internal static string BL_0025_ {
+ get {
+ return ResourceManager.GetString("BL(0025)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Unit Type mismatch {0} {1} ähnelt.
+ ///
+ internal static string BL_0026_ {
+ get {
+ return ResourceManager.GetString("BL(0026)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die {0} cannot be resolved ähnelt.
+ ///
+ internal static string BL_0027_ {
+ get {
+ return ResourceManager.GetString("BL(0027)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Cannot find function '{0}' ähnelt.
+ ///
+ internal static string BL_0028_ {
+ get {
+ return ResourceManager.GetString("BL(0028)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Target '{0}' cannot be found ähnelt.
+ ///
+ internal static string BL_0029_ {
+ get {
+ return ResourceManager.GetString("BL(0029)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Identifier '{0}' is not defined ähnelt.
+ ///
+ internal static string BL_0030_ {
+ get {
+ return ResourceManager.GetString("BL(0030)", resourceCulture);
+ }
+ }
+
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Cannot set type ähnelt.
+ ///
+ internal static string BL_0031_ {
+ get {
+ return ResourceManager.GetString("BL(0031)", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Source/Backlang.Codeanalysis/Properties/Resources.resx b/Source/Backlang.Codeanalysis/Properties/Resources.resx
new file mode 100644
index 00000000..01400d02
--- /dev/null
+++ b/Source/Backlang.Codeanalysis/Properties/Resources.resx
@@ -0,0 +1,216 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Expected Identifier, TupleType or Function-Signature as TypeLiteral, but got {0}
+
+
+ Invalid Modifier Combination
+
+
+ Unknown Character '{0}'
+
+
+ Unterminated Char-Literal
+
+
+ Unexpected Expression {0}
+
+
+ Unknown Literal {0}
+
+
+ Trailing comma is forbidden
+
+
+ Bitfield member declaration only allows literals
+
+
+ Expected Function, Property or Field-declaration for Type, but got {0}
+
+
+ Expected Type but got {0}
+
+
+ Unexpected Switch Option
+
+
+ Expected at least one catch block
+
+
+ SourceFile is empty
+
+
+ Expected Identifier but got {0}
+
+
+ Unterminated String-Literal
+
+
+ Multiline comment is not closed
+
+
+ Expected '{0}' but got '{1}'
+
+
+ Duplicate Modifier '{0}'
+
+
+ Namespace '{0}' already imported
+
+
+ Got OutputType 'Exe' but couldn't find entry point.
+
+
+ {0} cannot be found. Did you mean '{1}'?
+
+
+ Cannot implement '{0}', type not found
+
+
+ Cannot implement unit type '{0}'
+
+
+ '{0}' already declared
+
+
+ Type mismatch {0} {1}
+
+
+ Unit Type mismatch {0} {1}
+
+
+ {0} cannot be resolved
+
+
+ Cannot find function '{0}'
+
+
+ Target '{0}' cannot be found
+
+
+ Identifier '{0}' is not defined
+
+
+ Cannot set type
+
+
+ Cannot deduce Type. Declare it manually!
+
+
\ No newline at end of file
diff --git a/Source/Backlang.Contracts/Backlang.Contracts.csproj b/Source/Backlang.Contracts/Backlang.Contracts.csproj
index 6db8d956..8730ee04 100644
--- a/Source/Backlang.Contracts/Backlang.Contracts.csproj
+++ b/Source/Backlang.Contracts/Backlang.Contracts.csproj
@@ -3,7 +3,7 @@
net7.0
enable
- enable
+ disable
preview
True
True
@@ -16,11 +16,11 @@
-
-
+
+
-
+
diff --git a/Source/Backlang.Contracts/CompilerContext.cs b/Source/Backlang.Contracts/CompilerContext.cs
index 2bf1e0b1..4782f995 100644
--- a/Source/Backlang.Contracts/CompilerContext.cs
+++ b/Source/Backlang.Contracts/CompilerContext.cs
@@ -1,65 +1,46 @@
-namespace Backlang.Contracts;
+using Backlang.Codeanalysis.Core;
+
+namespace Backlang.Contracts;
#nullable disable
public sealed class CompilerContext
{
- public IEnumerable writeMethods;
-
public ICompilationTarget CompilationTarget;
public PluginContainer Plugins;
public DescribedAssembly Assembly { get; set; }
+ public PlaygroundData Playground { get; set; } = new();
+ public CompilerCliOptions Options { get; set; } = new();
+
+ public Stream OutputStream { get; set; }
+
public TypeResolver Binder { get; set; } = new();
public Scope GlobalScope { get; } = new(null);
- public Dictionary ImportetNamespaces { get; set; } = new();
+ public FileScopeData FileScope { get; set; } = new();
public List BodyCompilations { get; set; } = new();
public TypeEnvironment Environment { get; set; }
- [Option('i', "input", Required = true, HelpText = "Input files to be compiled.")]
- public IEnumerable InputFiles { get; set; }
-
public string[] MacroReferences { get; set; }
public List Messages { get; set; } = new();
- [Option('o', "output", Required = true, HelpText = "Output filename")]
- public string OutputFilename { get; set; }
-
public string OutputPath { get; set; }
- [Option('p', "print-tree", Required = false, HelpText = "Output files as tree")]
- public bool OutputTree { get; set; }
-
- [Option('t', "type", Required = false, HelpText = "Outputtype")]
- public string OutputType { get; set; }
-
public string ProjectFile { get; set; }
- [Option('r', "reference", Required = false, HelpText = "References of the assembly")]
- public IEnumerable References { get; set; } = Array.Empty();
-
public string ResultingOutputPath { get; set; }
- [Option("target", Required = false, HelpText = "For which platform to compile to")]
- public string Target { get; set; }
-
public string TempOutputPath { get; set; }
public List Trees { get; set; } = new();
- [Option('e', longName: "embedd", HelpText = "Embedd files into the assembly as resource")]
- public IEnumerable EmbeddedResource { get; set; }
-
public string CorLib { get; set; }
- [Option('v', longName: "version", HelpText = "Set the assembly version")]
- public string Version { get; set; }
-
- public void AddError(LNode node, string msg)
+ public void AddError(LNode node, LocalizableString msg)
{
if (node.Range.Source is not SourceFile) return;
diff --git a/Source/Backlang.Contracts/ConversionUtils.cs b/Source/Backlang.Contracts/ConversionUtils.cs
index 2c134dbe..6967f16b 100644
--- a/Source/Backlang.Contracts/ConversionUtils.cs
+++ b/Source/Backlang.Contracts/ConversionUtils.cs
@@ -39,11 +39,38 @@ public static void SetAccessModifier(LNode node, DescribedMember type, AccessMod
}
}
+ public static QualifiedName QualifyNamespace(string @namespace)
+ {
+ var spl = @namespace.Split('.');
+
+ QualifiedName? name = null;
+
+ foreach (var path in spl)
+ {
+ if (name == null)
+ {
+ name = new SimpleName(path).Qualify();
+ continue;
+ }
+
+ name = new SimpleName(path).Qualify(name.Value);
+ }
+
+ return name.Value;
+ }
+
public static QualifiedName GetQualifiedName(LNode lNode)
{
bool isPointer = false;
PointerKind pointerKind = PointerKind.Transient;
+
+ if (lNode is ("'suf.*", var ns))
+ {
+ var qualifiedNs = GetQualifiedName(ns);
+
+ return new SimpleName("*").Qualify(qualifiedNs);
+ }
if (lNode is ("#type*", var arg))
{
isPointer = true;
@@ -64,7 +91,7 @@ public static QualifiedName GetQualifiedName(LNode lNode)
if (lNode.ArgCount == 3 && lNode is ("#fn", var retType, _, var args))
{
- string typename = retType == LNode.Missing ? "Action`" + (args.ArgCount) : "Func`" + (args.ArgCount + 1);
+ string typename = retType.IsNoneType() ? "Action`" + (args.ArgCount) : "Func`" + (args.ArgCount + 1);
return new SimpleName(typename).Qualify("System");
}
diff --git a/Source/Backlang.Contracts/Datas/CompilerCliOptions.cs b/Source/Backlang.Contracts/Datas/CompilerCliOptions.cs
new file mode 100644
index 00000000..1ce4245a
--- /dev/null
+++ b/Source/Backlang.Contracts/Datas/CompilerCliOptions.cs
@@ -0,0 +1,40 @@
+namespace Backlang.Contracts;
+
+public class CompilerCliOptions
+{
+ public CompilerCliOptions()
+ {
+ References = Array.Empty();
+ EmbeddedResource = Array.Empty();
+ }
+
+ [Option('i', "input", Required = true, HelpText = "Input files to be compiled.")]
+ public IEnumerable InputFiles { get; set; }
+
+ [Option('o', "output", Required = true, HelpText = "Output filename")]
+ public string OutputFilename { get; set; }
+
+ [Option('p', "print-tree", Required = false, HelpText = "Output files as tree")]
+ public bool OutputTree { get; set; }
+
+ [Option('t', "type", Required = false, HelpText = "Outputtype")]
+ public string OutputType { get; set; }
+
+ [Option('r', "reference", Required = false, HelpText = "References of the assembly")]
+ public IEnumerable References { get; set; }
+
+ [Option("target", Required = false, HelpText = "For which platform to compile to")]
+ public string Target { get; set; }
+
+ [Option('e', longName: "embedd", HelpText = "Embedd files into the assembly as resource")]
+ public IEnumerable EmbeddedResource { get; set; }
+
+ [Option('v', longName: "version", HelpText = "Set the assembly version")]
+ public string Version { get; set; }
+
+ [Option('f', longName: "framework", HelpText = "On which framework should the assembly be runned on")]
+ public string TargetFramework { get; set; }
+
+ [Option("debug", HelpText = "Wait for debugger been attached for debugging plugins")]
+ public bool WaitForDebugger { get; set; }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Contracts/Datas/FileScopeData.cs b/Source/Backlang.Contracts/Datas/FileScopeData.cs
new file mode 100644
index 00000000..b4fbdcbf
--- /dev/null
+++ b/Source/Backlang.Contracts/Datas/FileScopeData.cs
@@ -0,0 +1,11 @@
+namespace Backlang.Contracts;
+
+public struct FileScopeData
+{
+ public FileScopeData()
+ {
+ ImportetNamespaces = new();
+ }
+
+ public Dictionary ImportetNamespaces { get; set; }
+}
diff --git a/Source/Backlang.Contracts/Datas/PlaygroundData.cs b/Source/Backlang.Contracts/Datas/PlaygroundData.cs
new file mode 100644
index 00000000..76d7dd1a
--- /dev/null
+++ b/Source/Backlang.Contracts/Datas/PlaygroundData.cs
@@ -0,0 +1,7 @@
+namespace Backlang.Contracts;
+
+public struct PlaygroundData
+{
+ public bool IsPlayground { get; set; }
+ public string Source { get; set; }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Contracts/Names.cs b/Source/Backlang.Contracts/Names.cs
index 73cb9841..bae58fcd 100644
--- a/Source/Backlang.Contracts/Names.cs
+++ b/Source/Backlang.Contracts/Names.cs
@@ -5,4 +5,5 @@ public static class Names
public static readonly string Extensions = "Extensions";
public static readonly string MainMethod = "Main";
public static readonly string FreeFunctions = "FreeFunctions";
+ public static readonly string ArrayValues = "''";
}
\ No newline at end of file
diff --git a/Source/Backlang.Contracts/NamespaceImports.cs b/Source/Backlang.Contracts/NamespaceImports.cs
index 5b692322..450019af 100644
--- a/Source/Backlang.Contracts/NamespaceImports.cs
+++ b/Source/Backlang.Contracts/NamespaceImports.cs
@@ -1,4 +1,6 @@
using Backlang.Driver;
+using Backlang.Codeanalysis.Core;
+using Backlang.Contracts.Scoping.Items;
namespace Backlang.Contracts;
@@ -14,13 +16,43 @@ public void ImportNamespace(LNode importStatement, CompilerContext context)
if (ImportedNamespaces.Contains(qualifiedNs))
{
- context.AddError(importStatement, $"Namespace '{qualifiedNs}' already imported");
+ context.AddError(importStatement, new(ErrorID.NamespaceAlreadyImported, qualifiedNs.ToString()));
return;
}
ImportedNamespaces.Add(qualifiedNs);
+
+ ExpandNamespaceImports(context);
}
}
+ private void ExpandNamespaceImports(CompilerContext context)
+ {
+ for (var i = 0; i < ImportedNamespaces.Count; i++)
+ {
+ var import = ImportedNamespaces[i];
+ var imp = import.ToString();
+
+ if (!imp.EndsWith(".*"))
+ {
+ continue;
+ }
+
+ var withoutWildcard = imp[..^2];
+
+ context.Binder.TryResolveNamespace(ConversionUtils.QualifyNamespace(withoutWildcard), out var foundNamespaces);
+ if (foundNamespaces == null)
+ {
+ //ToDo: add error that namespace has no subnamespace(s)
+ return;
+ }
+
+ ImportedNamespaces.Remove(import);
+ foreach (var foundNs in foundNamespaces.Namespaces)
+ {
+ ImportedNamespaces.Add(foundNs.Key.Qualify(withoutWildcard));
+ }
+ }
+ }
}
diff --git a/Source/Backlang.Contracts/Scoping/Scope.cs b/Source/Backlang.Contracts/Scoping/Scope.cs
index 055dc2f0..bb451ded 100644
--- a/Source/Backlang.Contracts/Scoping/Scope.cs
+++ b/Source/Backlang.Contracts/Scoping/Scope.cs
@@ -11,8 +11,10 @@ public class Scope
public Scope(Scope parent)
{
Parent = parent;
+ TypeAliases = new();
}
+ public Dictionary TypeAliases { get; set; }
public Scope Parent { get; set; }
public bool Add(ScopeItem item)
diff --git a/Source/Backlang.Contracts/Semantic/ModifierCheck.cs b/Source/Backlang.Contracts/Semantic/ModifierCheck.cs
new file mode 100644
index 00000000..5f6a0fd1
--- /dev/null
+++ b/Source/Backlang.Contracts/Semantic/ModifierCheck.cs
@@ -0,0 +1,35 @@
+using Backlang.Codeanalysis.Core;
+
+namespace Backlang.Contracts.Semantic;
+
+internal class ModifierCheck : ISemanticCheck
+{
+ public void Check(CompilationUnit tree, CompilerContext context)
+ {
+ var nodesWithModifiers = tree.Body
+ .SelectMany(_ => _.DescendantsAndSelf()).Where(IsModifiableNode).ToArray();
+
+ foreach (var node in nodesWithModifiers)
+ {
+ CheckForInvalidModifierCombination(node, context);
+ }
+ }
+
+ private void CheckForInvalidModifierCombination(LNode node, CompilerContext context)
+ {
+ var attrs = node.Attrs;
+ var condition = (attrs.Contains(LNode.Id(CodeSymbols.Public)) && attrs.Contains(LNode.Id(CodeSymbols.Private)))
+ || (attrs.Contains(LNode.Id(CodeSymbols.Public)) && attrs.Contains(LNode.Id(CodeSymbols.Internal)))
+ || (attrs.Contains(LNode.Id(CodeSymbols.Private)) && attrs.Contains(LNode.Id(CodeSymbols.Internal)));
+
+ if (condition)
+ {
+ context.AddError(node, ErrorID.InvalidModifierCombination);
+ }
+ }
+
+ private bool IsModifiableNode(LNode arg)
+ {
+ return arg.Calls(CodeSymbols.Class) || arg.Calls(CodeSymbols.Struct) || arg.Calls(CodeSymbols.Fn) || arg.Calls(Symbols.Bitfield);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Contracts/Semantic/VariableTypeCheck.cs b/Source/Backlang.Contracts/Semantic/VariableTypeCheck.cs
new file mode 100644
index 00000000..2d9ac775
--- /dev/null
+++ b/Source/Backlang.Contracts/Semantic/VariableTypeCheck.cs
@@ -0,0 +1,23 @@
+using Backlang.Codeanalysis.Core;
+using Backlang.Driver;
+
+namespace Backlang.Contracts.Semantic;
+
+internal class VariableTypeCheck : ISemanticCheck
+{
+ public void Check(CompilationUnit tree, CompilerContext context)
+ {
+ var letNodes = tree.Body.SelectMany(_ => _.Descendants()).Where(_ => _.Calls(CodeSymbols.Var)).ToArray();
+
+ foreach (var node in letNodes)
+ {
+ if (node is (_, (_, (_, var type)), (_, _, var value)))
+ {
+ if (type.Name.Name == "" && value.Calls(CodeSymbols.Void))
+ {
+ context.AddError(node, ErrorID.CannotDeduceType);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Contracts/SemanticChecker.cs b/Source/Backlang.Contracts/SemanticChecker.cs
index 7368263c..e78cce4b 100644
--- a/Source/Backlang.Contracts/SemanticChecker.cs
+++ b/Source/Backlang.Contracts/SemanticChecker.cs
@@ -9,6 +9,8 @@ public static class SemanticChecker
new ModuleDefinitionCheck(),
new ImportCheck(),
new TypenameCheck(),
+ new VariableTypeCheck(),
+ new ModifierCheck(),
new InterfaceNameCheck()
};
diff --git a/Source/Backlang.Core/Macros/BuiltInMacros.cs b/Source/Backlang.Core/Macros/BuiltInMacros.cs
index 213c2876..8245199f 100644
--- a/Source/Backlang.Core/Macros/BuiltInMacros.cs
+++ b/Source/Backlang.Core/Macros/BuiltInMacros.cs
@@ -26,6 +26,18 @@ public static LNode Todo(LNode node, IMacroContext context)
return LNode.Missing;
}
+ [LexicalMacro("notimplemented", "Semantic info for functionality that is not implemented", "notimplemented")]
+ public static LNode NotImplemented(LNode node, IMacroContext context)
+ {
+ return LNode.Missing;
+ }
+
+ [LexicalMacro("refactor", "Semantic info for functionality that needs to be refactored", "refactor")]
+ public static LNode Refactor(LNode node, IMacroContext context)
+ {
+ return LNode.Missing;
+ }
+
[LexicalMacro(@"nameof(id_or_expr)",
@"Converts the 'key' name component of an expression to a string (e.g. nameof(A.B(D)) == ""B"")", "nameof", Mode = MacroMode.MatchIdentifierOrCall)]
public static LNode @Nameof(LNode nameof, IMacroContext context)
diff --git a/Source/Backlang.Core/Macros/TestCustomMacros.cs b/Source/Backlang.Core/Macros/TestCustomMacros.cs
deleted file mode 100644
index 8826a959..00000000
--- a/Source/Backlang.Core/Macros/TestCustomMacros.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using LeMP;
-using Loyc.Syntax;
-
-namespace Backlang.Core.Macros;
-
-[ContainsMacros]
-public static class TestCustomMacros
-{
- [LexicalMacro("#matchCode(expr) {}", "match code", "matchCode", Mode = MacroMode.MatchIdentifierOrCall)]
- public static LNode matchCode(LNode node, IMacroContext context)
- {
- return node.With(LNode.Id("macro executed"), LNode.List(node.Args[0]));
- }
-
- [LexicalMacro("#someMacro {}", "some Macro", "someMacro", Mode = MacroMode.MatchIdentifierOrCall)]
- public static LNode someMacro(LNode node, IMacroContext context)
- {
- return LNode.Id("macro executed");
- }
-}
\ No newline at end of file
diff --git a/Source/Backlang.Core/Result.cs b/Source/Backlang.Core/Result.cs
index e4714c10..3a1f07ec 100644
--- a/Source/Backlang.Core/Result.cs
+++ b/Source/Backlang.Core/Result.cs
@@ -1,4 +1,6 @@
-namespace Backlang.Core
+using System.Runtime.CompilerServices;
+
+namespace Backlang.Core
{
public class Result
{
@@ -9,14 +11,16 @@ public Result(T value)
_value = value;
}
- public static implicit operator bool(Result value)
+ public static implicit operator T(Result value)
{
- return value._value != null;
+ return value._value;
}
- public static implicit operator T(Result value)
+ //Unpacking operator
+ [SpecialName]
+ public static bool op_Unpacking(Result value)
{
- return value._value;
+ return value._value != null;
}
}
}
\ No newline at end of file
diff --git a/Source/Backlang.Core/Sealed.cs b/Source/Backlang.Core/Sealed.cs
new file mode 100644
index 00000000..8b88cdc3
--- /dev/null
+++ b/Source/Backlang.Core/Sealed.cs
@@ -0,0 +1,46 @@
+using System.Runtime.CompilerServices;
+
+namespace Backlang.Core;
+
+public struct Sealed
+{
+ private T _value;
+
+ public bool IsFreezed { get; private set; }
+
+ public static implicit operator Sealed(T value)
+ {
+ return new Sealed { _value = value, IsFreezed = true };
+ }
+
+ public static implicit operator T(Sealed @sealed)
+ {
+ return @sealed._value;
+ }
+
+ public void Set(T value)
+ {
+ if (IsFreezed)
+ {
+ throw new InvalidOperationException("Object is freezed");
+ }
+ _value = value;
+ }
+
+ public void Freeze()
+ {
+ IsFreezed = true;
+ }
+
+ public void Unfreeze()
+ {
+ IsFreezed = false;
+ }
+
+ //Unpacking operator
+ [SpecialName]
+ public static T op_Unpacking(Sealed value)
+ {
+ return value._value;
+ }
+}
diff --git a/Source/Backlang.Driver/Backlang.Driver.csproj b/Source/Backlang.Driver/Backlang.Driver.csproj
index 97ffb438..d96664f2 100644
--- a/Source/Backlang.Driver/Backlang.Driver.csproj
+++ b/Source/Backlang.Driver/Backlang.Driver.csproj
@@ -27,14 +27,15 @@
-
-
+
+
-
+
+
-
+
diff --git a/Source/Backlang.Driver/BinderExtensions.cs b/Source/Backlang.Driver/BinderExtensions.cs
new file mode 100644
index 00000000..2ff9545b
--- /dev/null
+++ b/Source/Backlang.Driver/BinderExtensions.cs
@@ -0,0 +1,80 @@
+using System.Collections.Concurrent;
+
+namespace Backlang.Driver;
+
+public static class BinderExtensions
+{
+ private static readonly ConcurrentDictionary _functionCache = new();
+
+ ///
+ /// Finds a method based on a selector
+ ///
+ ///
+ /// System.StringBuilder::AppendLine(System.String)
+ ///
+ public static IMethod FindFunction(this TypeResolver binder, string selector)
+ {
+ if (_functionCache.ContainsKey(selector))
+ {
+ return _functionCache[selector];
+ }
+
+ var convertedSelector = GetSelector(selector);
+
+ var type = binder.ResolveTypes(convertedSelector.Typename)?.FirstOrDefault();
+
+ if(type == null) {
+ throw new Exception($"Type '{type.FullName}' not found");
+ }
+
+ var methods = type.Methods
+ .Where(_ => _.Name.ToString() == convertedSelector.FunctionName)
+ .Where(_ => _.Parameters.Count == convertedSelector.ParameterTypes.Length);
+
+ foreach (var method in methods)
+ {
+ for (int i = 0; i < method.Parameters.Count; i++)
+ {
+ if (method.Parameters[i].Type.FullName.ToString() == convertedSelector.ParameterTypes[i])
+ {
+ _functionCache.AddOrUpdate(selector, _ => method, (_, __) => __);
+ return method;
+ }
+ }
+ }
+
+ var function = methods.FirstOrDefault();
+ if (function != null)
+ {
+ _functionCache.AddOrUpdate(selector, _ => methods.FirstOrDefault(), (_, __) => __);
+ }
+
+ return methods.FirstOrDefault();
+ }
+
+ private static FunctionSelector GetSelector(string selector)
+ {
+ var ms = new FunctionSelector();
+
+ var spl = selector.Split("::");
+
+ ms.Typename = ConversionUtils.QualifyNamespace(spl[0]);
+
+ var methodPart = spl[1];
+ ms.FunctionName = methodPart.Substring(0, methodPart.IndexOf("("));
+
+ var parameterPart = methodPart[ms.FunctionName.Length..].Trim('(', ')');
+ ms.ParameterTypes = parameterPart
+ .Split(",", StringSplitOptions.RemoveEmptyEntries)
+ .ToArray();
+
+ return ms;
+ }
+
+ private class FunctionSelector
+ {
+ public QualifiedName Typename { get; set; }
+ public string FunctionName { get; set; }
+ public string[] ParameterTypes { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/CompilerDriver.cs b/Source/Backlang.Driver/CompilerDriver.cs
index 524329ee..90526acc 100644
--- a/Source/Backlang.Driver/CompilerDriver.cs
+++ b/Source/Backlang.Driver/CompilerDriver.cs
@@ -11,10 +11,14 @@ public static async void Compile(CompilerContext context)
var pipeline = Flo.Pipeline.Build(
cfg => {
+ cfg.When(_ => _.Options.WaitForDebugger, _ => {
+ _.Add();
+ });
+
cfg.Add();
cfg.Add();
- cfg.When(_ => !hasError(_.Messages) && _.OutputTree, _ => {
+ cfg.When(_ => !hasError(_.Messages) && _.Options.OutputTree, _ => {
_.Add();
});
diff --git a/Source/Backlang.Driver/Compiling/IRGenerator.cs b/Source/Backlang.Driver/Compiling/IRGenerator.cs
index 9bbd13d2..84a8c530 100644
--- a/Source/Backlang.Driver/Compiling/IRGenerator.cs
+++ b/Source/Backlang.Driver/Compiling/IRGenerator.cs
@@ -3,11 +3,83 @@
using Furesoft.Core.CodeDom.Compiler.Flow;
using Furesoft.Core.CodeDom.Compiler.Instructions;
using Furesoft.Core.CodeDom.Compiler.TypeSystem;
+using System.Numerics;
namespace Backlang.Driver.Compiling;
public static class IRGenerator
{
+ private static readonly int[] _primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
+
+ public static void GenerateGetHashCode(CompilerContext context, DescribedType type)
+ {
+ var gethashcodeMethod = new DescribedBodyMethod(type, new SimpleName("GetHashCode"),
+ false, context.Environment.Int32);
+ gethashcodeMethod.IsPublic = true;
+ gethashcodeMethod.IsOverride = true;
+
+ var graph = Utils.CreateGraphBuilder();
+
+ var block = graph.EntryPoint;
+
+ block.AppendParameter(new BlockParameter(context.Environment.Int32, "hash"));
+
+ var startPrime = SelectPrime();
+ var constant = block.AppendInstruction(
+ Instruction.CreateLoad(context.Environment.Int32, block.AppendInstruction(
+ Instruction.CreateConstant(new IntegerConstant(startPrime), context.Environment.Int32))
+ )
+ );
+
+ block.AppendInstruction(Instruction.CreateAlloca(context.Environment.Int32));
+
+ foreach (var field in type.Fields)
+ {
+ var methods = field.FieldType.Methods.Where(_ => _.Name.ToString() == "GetHashCode");
+ if (methods.Any())
+ {
+ var method = methods.First();
+
+ // hash = hash * 23 + field.GetHashCode();
+ var loadHash = Instruction.CreateLoadLocal(new Parameter(context.Environment.Int32, "hash"));
+ var hash = block.AppendInstruction(loadHash);
+ var c = block.AppendInstruction(
+ Instruction.CreateLoad(context.Environment.Int32, block.AppendInstruction(
+ Instruction.CreateConstant(new IntegerConstant(SelectPrime()), context.Environment.Int32))
+ )
+ );
+
+ var multiplication = block.AppendInstruction(Instruction.CreateBinaryArithmeticIntrinsic("*", false, context.Environment.Int32, hash, c));
+
+ block.AppendInstruction(Instruction.CreateLoadArg(new Parameter(type)));
+ var instruction = Instruction.CreateLoadField(field);
+
+ if (field.FieldType.BaseTypes.Count() > 0 && field.FieldType.BaseTypes[0].FullName.ToString() == "System.ValueType")
+ {
+ instruction = Instruction.CreateGetFieldPointer(field, null);
+ }
+
+ var ldField = block.AppendInstruction(instruction);
+ var call = block.AppendInstruction(Instruction.CreateCall(method, MethodLookup.Virtual, new List() { ldField }));
+
+ var addition = block.AppendInstruction(Instruction.CreateBinaryArithmeticIntrinsic("+", false, context.Environment.Int32, ldField, multiplication));
+
+ block.AppendInstruction(Instruction.CreateStore(context.Environment.Int32, hash, addition));
+ }
+ }
+
+ block.AppendInstruction(Instruction.CreateLoadLocal(new Parameter(context.Environment.Int32, "hash")));
+ block.Flow = new ReturnFlow();
+
+ gethashcodeMethod.Body = new MethodBody(new Parameter(), new Parameter(type), EmptyArray.Value, graph.ToImmutable());
+ type.AddMethod(gethashcodeMethod);
+ }
+
+ private static int SelectPrime()
+ {
+ return _primes[Random.Shared.Next(0, _primes.Length)];
+ }
+
public static void GenerateToString(CompilerContext context, DescribedType type)
{
var toStringMethod = new DescribedBodyMethod(type, new SimpleName("ToString"), false, Utils.ResolveType(context.Binder, typeof(string)));
@@ -23,7 +95,8 @@ public static void GenerateToString(CompilerContext context, DescribedType type)
var p = block.AppendParameter(new BlockParameter(sbType, varname));
var ctor = sbType.Methods.First(_ => _.IsConstructor && _.Parameters.Count == 0);
- var appendLineMethod = sbType.Methods.First(_ => _.Name.ToString() == "AppendLine" && _.Parameters.Count == 1 && _.Parameters[0].Type.Name.ToString() == "String");
+
+ var appendLineMethod = context.Binder.FindFunction("System.Text.StringBuilder::AppendLine(System.String)");
block.AppendInstruction(Instruction.CreateNewObject(ctor, new List()));
block.AppendInstruction(Instruction.CreateAlloca(sbType));
@@ -34,23 +107,21 @@ public static void GenerateToString(CompilerContext context, DescribedType type)
foreach (var field in type.Fields)
{
+ //AppendThis(block, p.Type);
+
var loadSbf = block.AppendInstruction(Instruction.CreateLoadLocal(new Parameter(p.Type, p.Tag.Name)));
AppendLine(context, block, appendLineMethod, loadSbf, field.Name + " = ");
var value = AppendLoadField(block, field);
- var callee = sbType.Methods.FirstOrDefault(_ => _.Name.ToString() == "Append" && _.Parameters.Count == 1 && _.Parameters[0].Type.Name.ToString() == field.FieldType.Name.ToString());
+ var appendMethod = context.Binder.FindFunction($"System.Text.StringBuilder::Append({field.FieldType.FullName})");
- if (callee == null)
- {
- callee = sbType.Methods.First(_ => _.Parameters.Count == 1 && _.Parameters[0].Type.FullName.ToString() == "System.Object");
- }
+ appendMethod ??= context.Binder.FindFunction("System.Text.StringBuilder::Append(System.Object)");
- block.AppendInstruction(Instruction.CreateCall(callee, MethodLookup.Virtual, new List { loadSbf, value }));
+ block.AppendInstruction(Instruction.CreateCall(appendMethod, MethodLookup.Virtual, new List { loadSbf, value }));
}
- var tsM = sbType.Methods.First(_ => _.Name.ToString() == "ToString");
-
+ var tsM = context.Binder.FindFunction($"System.Text.StringBuilder::ToString()");
block.AppendInstruction(Instruction.CreateCall(tsM, MethodLookup.Virtual, new List { loadSb }));
block.Flow = new ReturnFlow();
@@ -60,6 +131,26 @@ public static void GenerateToString(CompilerContext context, DescribedType type)
type.AddMethod(toStringMethod);
}
+ public static void GenerateEmptyCtor(CompilerContext context, DescribedType type)
+ {
+ var ctorMethod = new DescribedBodyMethod(type, new SimpleName(".ctor"), false, Utils.ResolveType(context.Binder, typeof(void)))
+ {
+ IsConstructor = true
+ };
+
+ ctorMethod.IsPublic = true;
+
+ var graph = Utils.CreateGraphBuilder();
+
+ var block = graph.EntryPoint;
+
+ block.Flow = new ReturnFlow();
+
+ ctorMethod.Body = new MethodBody(new Parameter(), Parameter.CreateThisParameter(type), EmptyArray.Value, graph.ToImmutable());
+
+ type.AddMethod(ctorMethod);
+ }
+
public static void GenerateDefaultCtor(CompilerContext context, DescribedType type)
{
var ctorMethod = new DescribedBodyMethod(type, new SimpleName(".ctor"), false, Utils.ResolveType(context.Binder, typeof(void)))
diff --git a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/CompileTargetStage.cs b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/CompileTargetStage.cs
index bf9c789b..245b0424 100644
--- a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/CompileTargetStage.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/CompileTargetStage.cs
@@ -1,4 +1,5 @@
-using Backlang.Core.CompilerService;
+using Backlang.Codeanalysis.Core;
+using Backlang.Core.CompilerService;
using Backlang.Driver.Compiling.Targets.Dotnet;
using Flo;
using Furesoft.Core.CodeDom.Compiler.Pipeline;
@@ -14,21 +15,27 @@ public async Task HandleAsync(CompilerContext context, Func _expressions = new List()
@@ -28,9 +35,11 @@ public partial class ImplementationStage
new ArrayExpressionImplementor(),
new DefaultExpressionImplementor(),
new TypeOfExpressionImplementor(),
+ new AsExpressionImplementor(),
new AddressExpressionImplementor(),
new CtorExpressionImplementor(),
new UnaryExpressionImplementor(),
+ new MemberExpressionImplementor(),
new BinaryExpressionImplementor(),
new IdentifierExpressionImplementor(),
new PointerExpressionImplementor(),
@@ -45,8 +54,16 @@ public static MethodBody CompileBody(LNode function, CompilerContext context, IM
{
var graph = Utils.CreateGraphBuilder();
var block = graph.EntryPoint;
+ var branchLabels = new BranchLabels();
- AppendBlock(function.Args[3], block, context, method, modulename, scope);
+ var afterBlock = AppendBlock(function.Args[3], block, context, method, modulename, scope, branchLabels);
+
+ SetReturnType((DescribedBodyMethod)method, function, context, scope, modulename.Value);
+
+ if (afterBlock.Flow is NothingFlow && method.ReturnParameter.Type.FullName.ToString() != "System.Void")
+ {
+ afterBlock.Flow = new ReturnFlow();
+ }
return new MethodBody(
method.ReturnParameter,
@@ -55,8 +72,10 @@ public static MethodBody CompileBody(LNode function, CompilerContext context, IM
graph.ToImmutable());
}
- public static BasicBlockBuilder AppendBlock(LNode blkNode, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope)
+ public static BasicBlockBuilder AppendBlock(LNode blkNode, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels)
{
+ block.Flow = new NothingFlow();
+
foreach (var node in blkNode.Args)
{
if (!node.IsCall) continue;
@@ -65,67 +84,22 @@ public static BasicBlockBuilder AppendBlock(LNode blkNode, BasicBlockBuilder blo
{
if (node.ArgCount == 0) continue;
- block = AppendBlock(node, block.Graph.AddBasicBlock(), context, method, modulename, scope.CreateChildScope());
+ block = AppendBlock(node, block.Graph.AddBasicBlock(), context, method, modulename, scope.CreateChildScope(), branchLabels);
continue;
}
if (_implementations.ContainsKey(node.Name))
{
- block = _implementations[node.Name].Implement(context, method, block, node, modulename, scope);
-
- if (block == null)
- return block;
- }
- else if (node.Calls("print"))
- {
- AppendCall(context, block, node, context.writeMethods, scope, modulename.Value, methodName: "Write");
- }
- else if (node.Calls("println"))
- {
- AppendCall(context, block, node, context.writeMethods, scope, modulename.Value, methodName: "WriteLine");
+ block = _implementations[node.Name].Implement(node, block, context, method, modulename, scope, branchLabels);
}
else
{
- //ToDo: continue implementing static function call in same type
- var type = (DescribedType)method.ParentType;
- var calleeName = node.Target;
- var methods = type.Methods;
-
- if (!methods.Any(_ => _.Name.ToString() == calleeName.ToString()))
- {
- type = (DescribedType)context.Binder.ResolveTypes(new SimpleName(Names.FreeFunctions).Qualify(modulename.Value)).FirstOrDefault();
-
- if (type == null)
- {
- context.AddError(node, $"Cannot find function '{calleeName}'");
- }
- }
-
- if (scope.TryGet(calleeName.Name.Name, out var callee))
- {
- if (type.IsStatic && !callee.IsStatic)
- {
- context.AddError(node, $"A non static function '{calleeName.Name.Name}' cannot be called in a static function.");
- return block;
- }
-
- //ToDo: add overload AppendCall with known callee
- AppendCall(context, block, node, type.Methods, scope, modulename.Value);
- }
- else
- {
- var suggestion = LevensteinDistance.Suggest(calleeName.Name.Name, type.Methods.Select(_ => _.Name.ToString()));
-
- context.AddError(node, $"Cannot find function '{calleeName.Name.Name}'. Did you mean '{suggestion}'?");
- }
+ EmitFunctionCall(method, node, block, context, scope, modulename);
}
}
//automatic dtor call
- foreach (var v in block.Parameters)
- {
- AppendDtor(context, block, scope, modulename, v.Tag.Name);
- }
+ AppendAllDtors(block, context, modulename, scope);
return block;
}
@@ -165,6 +139,11 @@ public static NamedInstructionBuilder AppendDtor(CompilerContext context, BasicB
{
if (scope.TryGet(varname, out var scopeItem))
{
+ if (!scopeItem.Type.Methods.Any(_ => _.Name.ToString() == "Finalize"))
+ {
+ return null;
+ }
+
block.AppendInstruction(Instruction.CreateLoadLocal(scopeItem.Parameter));
return AppendCall(context, block, LNode.Missing, scopeItem.Type.Methods, scope, modulename, false, "Finalize");
@@ -230,7 +209,7 @@ public static List AppendCallArguments(CompilerContext context, BasicB
{
var suggestion = LevensteinDistance.Suggest(arg.Name.Name, scope.GetAllScopeNames());
- context.AddError(arg, $"{arg.Name.Name} cannot be found. Did you mean '{suggestion}'?");
+ context.AddError(arg, new(ErrorID.CannotBeFoundDidYouMean, arg.Name.Name, suggestion));
}
}
}
@@ -238,6 +217,69 @@ public static List AppendCallArguments(CompilerContext context, BasicB
return callTags;
}
+ public static void AppendAllDtors(BasicBlockBuilder block, CompilerContext context, QualifiedName? modulename, Scope scope)
+ {
+ foreach (var v in block.Parameters)
+ {
+ AppendDtor(context, block, scope, modulename, v.Tag.Name);
+ }
+ }
+
+ private static void SetReturnType(DescribedBodyMethod method, LNode function, CompilerContext context, Scope scope, QualifiedName modulename)
+ {
+ var retType = function.Args[0];
+
+ if (retType.Name != LNode.Missing.Name)
+ {
+ var rtype = TypeInheritanceStage.ResolveTypeWithModule(retType, context, modulename);
+
+ method.ReturnParameter = new Parameter(rtype);
+ }
+ else
+ {
+ var deducedReturnType = TypeDeducer.DeduceFunctionReturnType(function, context, scope, modulename);
+
+ method.ReturnParameter = deducedReturnType != null ? new Parameter(deducedReturnType) : new Parameter(Utils.ResolveType(context.Binder, typeof(void)));
+ }
+ }
+
+ private static BasicBlockBuilder EmitFunctionCall(IMethod method, LNode node, BasicBlockBuilder block, CompilerContext context, Scope scope, QualifiedName? moduleName)
+ {
+ //ToDo: continue implementing static function call in same type
+ var type = (DescribedType)method.ParentType;
+ var calleeName = node.Target;
+ var methods = type.Methods;
+
+ if (!methods.Any(_ => _.Name.ToString() == calleeName.ToString()))
+ {
+ type = (DescribedType)context.Binder.ResolveTypes(new SimpleName(Names.FreeFunctions).Qualify(moduleName.Value)).FirstOrDefault();
+
+ if (type == null)
+ {
+ context.AddError(node, new(ErrorID.CannotFindFunction, calleeName.ToString()));
+ }
+ }
+
+ if (scope.TryGet(calleeName.Name.Name, out var callee))
+ {
+ if (type.IsStatic && !callee.IsStatic)
+ {
+ context.AddError(node, $"A non static function '{calleeName.Name.Name}' cannot be called in a static function.");
+ return block;
+ }
+
+ AppendCall(context, block, node, type.Methods, scope, moduleName.Value);
+ }
+ else
+ {
+ var suggestion = LevensteinDistance.Suggest(calleeName.Name.Name, type.Methods.Select(_ => _.Name.ToString()));
+
+ context.AddError(node, new(ErrorID.CannotBeFoundDidYouMean, calleeName.Name.Name, suggestion));
+ }
+
+ return block;
+ }
+
private static void ConvertMethodBodies(CompilerContext context)
{
foreach (var bodyCompilation in context.BodyCompilations)
diff --git a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/ImplementationStage.Helpers.cs b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/ImplementationStage.Helpers.cs
index dcf36b13..32bcd961 100644
--- a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/ImplementationStage.Helpers.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/ImplementationStage.Helpers.cs
@@ -7,6 +7,7 @@ public sealed partial class ImplementationStage : IHandler LiteralTypeMap = new Dictionary
{
+ [CodeSymbols.Object] = typeof(object),
[CodeSymbols.Bool] = typeof(bool),
[CodeSymbols.String] = typeof(string),
@@ -32,6 +33,7 @@ public enum ConditionalJumpKind
NotEquals,
Equals,
True,
+ False,
}
public static IType GetLiteralType(LNode value, CompilerContext context, Scope scope, QualifiedName? modulename)
@@ -146,19 +148,24 @@ public static bool MatchesParameters(IMethod method, List argTypes)
public static IMethod GetMatchingMethod(CompilerContext context, List argTypes, IEnumerable methods, string methodname, bool shouldAppendError = true)
{
+ var candiates = new List();
foreach (var m in methods.Where(_ => _.Name.ToString() == methodname))
{
if (m.Parameters.Count == argTypes.Count)
{
if (MatchesParameters(m, argTypes))
- return m;
+ candiates.Add(m);
}
}
- if (shouldAppendError)
+ if (shouldAppendError && candiates.Count == 0)
{
context.Messages.Add(Message.Error($"Cannot find matching function '{methodname}({string.Join(", ", argTypes.Select(_ => _.FullName.ToString()))})'"));
+ return null;
}
- return null;
+
+ //ToDo: refactor getting best candidate
+ var orderedCandidates = candiates.OrderByDescending(_ => _.Parameters.Select(__ => _.FullName.ToString()).Contains("System.Object"));
+ return orderedCandidates.FirstOrDefault();
}
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/ImplementationStage.cs b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/ImplementationStage.cs
index 4214fd3b..077b8391 100644
--- a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/ImplementationStage.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/ImplementationStage.cs
@@ -1,3 +1,4 @@
+using Backlang.Codeanalysis.Core;
using Backlang.Contracts.Scoping.Items;
using Flo;
using Furesoft.Core.CodeDom.Compiler.TypeSystem;
@@ -43,6 +44,13 @@ private static void ImplementDefaultsForStructs(CompilerContext context, LNode s
{
IRGenerator.GenerateDefaultCtor(context, type);
}
+
+ IRGenerator.GenerateEmptyCtor(context, type);
+
+ if (!type.Methods.Any(_ => _.Name.ToString() == "GetHashCode" && _.Parameters.Count == 0))
+ {
+ IRGenerator.GenerateGetHashCode(context, type);
+ }
}
private static void CollectImplementations(CompilerContext context, LNode st, QualifiedName modulename)
@@ -65,13 +73,13 @@ private static void CollectImplementations(CompilerContext context, LNode st, Qu
if (targetType == null)
{
- context.AddError(typenode, $"Cannot implement '{fullname.FullName}', type not found");
+ context.AddError(typenode, new(ErrorID.CannotImplementTypeNotFound, fullname.FullName));
return;
}
if (Utils.IsUnitType(context, targetType))
{
- context.AddError(typenode, $"Cannot implement unit type '{fullname.FullName}'");
+ context.AddError(typenode, new(ErrorID.CannotImplementUnitType, fullname.FullName));
}
typeScope = context.GlobalScope.CreateChildScope();
@@ -99,6 +107,9 @@ private static void CollectImplementations(CompilerContext context, LNode st, Qu
IsStatic = true,
IsPublic = true
};
+
+ Utils.AddCompilerGeneratedAttribute(context.Binder, extensionType);
+
context.Assembly.AddType(extensionType);
}
diff --git a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/IntermediateStage.cs b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/IntermediateStage.cs
index 2ba7c661..c20aedbd 100644
--- a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/IntermediateStage.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/IntermediateStage.cs
@@ -9,7 +9,7 @@ public sealed class IntermediateStage : IHandler HandleAsync(CompilerContext context, Func> next)
{
- context.Assembly = new DescribedAssembly(new QualifiedName(context.OutputFilename.Replace(".dll", "")));
+ context.Assembly = new DescribedAssembly(new QualifiedName(context.Options.OutputFilename.Replace(".dll", "")));
foreach (var tree in context.Trees)
{
@@ -22,11 +22,15 @@ public async Task HandleAsync(CompilerContext context, Func GetNamespaceImports(CompilationUnit cu, CompilerContext context)
{
for (var i = 0; i < cu.Body.Count; i++)
@@ -124,10 +137,12 @@ private IEnumerable GetNamespaceImports(CompilationUnit cu, CompilerConte
private void ConvertUnitDeclaration(CompilerContext context, LNode st, QualifiedName modulename, Scope globalScope)
{
- var unitType = new DescribedType(new SimpleName(st[0].Name.ToString()).Qualify(modulename), context.Assembly);
-
- unitType.IsStatic = true;
- unitType.IsPublic = true;
+ var unitType = new DescribedType(
+ new SimpleName(st[0].Name.ToString()).Qualify(modulename), context.Assembly)
+ {
+ IsStatic = true,
+ IsPublic = true
+ };
unitType.AddAttribute(new DescribedAttribute(Utils.ResolveType(context.Binder, typeof(Backlang.Core.CompilerService.UnitTypeAttribute))));
@@ -179,7 +194,9 @@ private void ConvertDiscriminatedUnion(CompilerContext context, LNode discrim, Q
discType.AddField(fieldType);
}
+ IRGenerator.GenerateGetHashCode(context, discType);
IRGenerator.GenerateDefaultCtor(context, discType);
+ IRGenerator.GenerateEmptyCtor(context, discType);
IRGenerator.GenerateToString(context, discType);
}
}
diff --git a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/TypeInheritanceStage.ConvertFunction.cs b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/TypeInheritanceStage.ConvertFunction.cs
index 3ae13f54..f15fcfdf 100644
--- a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/TypeInheritanceStage.ConvertFunction.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/TypeInheritanceStage.ConvertFunction.cs
@@ -43,7 +43,6 @@ public static DescribedBodyMethod ConvertFunction(CompilerContext context, Descr
var scope = parentScope.CreateChildScope();
AddParameters(method, function, context, modulename, scope);
- SetReturnType(method, function, context, modulename);
if (methodName == ".ctor")
{
@@ -100,9 +99,11 @@ private static void ConvertFreeFunction(CompilerContext context, LNode node, Qua
if (!context.Assembly.Types.Any(_ =>
_.FullName.ToString() == new SimpleName(Names.FreeFunctions).Qualify(modulename).ToString()))
{
- type = new DescribedType(new SimpleName(Names.FreeFunctions).Qualify(modulename), context.Assembly);
- type.IsStatic = true;
- type.IsPublic = true;
+ type = new DescribedType(new SimpleName(Names.FreeFunctions).Qualify(modulename), context.Assembly)
+ {
+ IsStatic = true,
+ IsPublic = true
+ };
context.Assembly.AddType(type);
var tr = new TypeResolver();
@@ -146,13 +147,4 @@ private static Parameter ConvertParameter(LNode p, CompilerContext context, Qual
return param;
}
-
- private static void SetReturnType(DescribedBodyMethod method, LNode function, CompilerContext context, QualifiedName modulename)
- {
- var retType = function.Args[0];
-
- var rtype = ResolveTypeWithModule(retType, context, modulename);
-
- method.ReturnParameter = new Parameter(rtype);
- }
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/TypeInheritanceStage.Resolving.cs b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/TypeInheritanceStage.Resolving.cs
index bdd8b50c..da63dc2a 100644
--- a/Source/Backlang.Driver/Compiling/Stages/CompilationStages/TypeInheritanceStage.Resolving.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/CompilationStages/TypeInheritanceStage.Resolving.cs
@@ -1,5 +1,6 @@
using Backlang.Contracts.TypeSystem;
using Flo;
+using Loyc.Geometry;
namespace Backlang.Driver.Compiling.Stages;
@@ -50,53 +51,35 @@ public static IType ResolveTypeWithModule(LNode typeNode, CompilerContext contex
}
IType resolvedType;
- if (TypenameTable.ContainsKey(fullName.ToString()))
+
+ if (context.GlobalScope.TypeAliases.ContainsKey(fullName.ToString()))
+ {
+ resolvedType = context.GlobalScope.TypeAliases[fullName.ToString()];
+ }
+ else if (TypenameTable.ContainsKey(fullName.ToString()))
{
resolvedType = Utils.ResolveType(context.Binder, TypenameTable[fullName.FullName]);
if (typeNode is (_, (_, _, (_, var unit))) && unit != LNode.Missing)
{
- if (unit is (_, (_, var u)))
- {
- var resolvedUnit = ResolveTypeWithModule(u, context, modulename);
-
- if (!Utils.IsUnitType(context, resolvedUnit))
- {
- context.AddError(u, $"{resolvedUnit} is not a unit type");
- }
-
- resolvedType = new UnitType(resolvedType, resolvedUnit);
- }
+ ResolveUnitType(context, modulename, ref resolvedType, unit);
}
}
+ else if (typeNode is ("#type?", var nullableArg))
+ {
+ resolvedType = ResolveNullableType(nullableArg, context, modulename);
+ }
else if (fullName is ("System", var func) && (func.StartsWith("Action") || func.StartsWith("Func")))
{
- var fnType = Utils.ResolveType(context.Binder, func, "System");
-
- var funcArgs = new List();
- foreach (var garg in typeNode.Args[2].Args)
- {
- funcArgs.Add(ResolveTypeWithModule(garg, context, modulename));
- }
-
- resolvedType = fnType.MakeGenericType(funcArgs);
+ resolvedType = ResolveFunctionType(typeNode, context, modulename, func);
}
else if (typeNode.Calls(CodeSymbols.Tuple))
{
- var tupleType = Utils.ResolveType(context.Binder, $"Tuple`{typeNode.ArgCount}", "System");
-
- var tupleArgs = new List();
- foreach (var garg in typeNode.Args)
- {
- tupleArgs.Add(ResolveTypeWithModule(garg, context, modulename));
- }
-
- resolvedType = tupleType.MakeGenericType(tupleArgs);
+ resolvedType = ResolveTupleType(typeNode, context, modulename);
}
else if (typeNode.Calls(CodeSymbols.Array))
{
- resolvedType = ResolveTypeWithModule(typeNode[0], context, modulename);
- resolvedType = context.Environment.MakeArrayType(resolvedType, (int)typeNode[1].Value);
+ resolvedType = ResolveArrayType(typeNode, context, modulename);
}
else
{
@@ -109,23 +92,15 @@ public static IType ResolveTypeWithModule(LNode typeNode, CompilerContext contex
if (resolvedType == null)
{
- if (context.ImportetNamespaces.ContainsKey(typeNode.Range.Source.FileName))
+ if (context.FileScope.ImportetNamespaces.TryGetValue(typeNode.Range.Source.FileName, out var importedNamespaces))
{
- var namespaceImport = context.ImportetNamespaces[typeNode.Range.Source.FileName];
-
- foreach (var importedNs in namespaceImport.ImportedNamespaces)
- {
- var tmpName = fullName.Qualify(importedNs);
-
- resolvedType = context.Binder.ResolveTypes(tmpName).FirstOrDefault();
-
- if (resolvedType != null) break;
- }
+ ResolveImportedType(typeNode, context, ref fullName, ref resolvedType);
}
if (resolvedType == null && !string.IsNullOrEmpty(fullName.ToString()))
{
context.AddError(typeNode, $"Type {fullName} cannot be found");
+ return null;
}
}
}
@@ -137,4 +112,85 @@ public static IType ResolveTypeWithModule(LNode typeNode, CompilerContext contex
return resolvedType;
}
+
+ private static IType ResolveNullableType(LNode nullableArg, CompilerContext context, QualifiedName modulename)
+ {
+ var tupleType = Utils.ResolveType(context.Binder, $"Nullable`1", "System");
+
+ var innerType = ResolveTypeWithModule(nullableArg, context, modulename);
+
+ return tupleType.MakeGenericType(new List() { innerType });
+ }
+
+ private static void ResolveImportedType(LNode typeNode, CompilerContext context, ref QualifiedName fullName, ref IType resolvedType)
+ {
+ var namespaceImport = context.FileScope.ImportetNamespaces[typeNode.Range.Source.FileName];
+
+ foreach (var importedNs in namespaceImport.ImportedNamespaces)
+ {
+ var tmpName = fullName.Qualify(importedNs);
+
+ resolvedType = context.Binder.ResolveTypes(tmpName).FirstOrDefault();
+
+ if (resolvedType != null) break;
+ }
+ }
+
+ private static IType ResolveArrayType(LNode typeNode, CompilerContext context, QualifiedName modulename)
+ {
+ IType resolvedType;
+ var arrType = ResolveTypeWithModule(typeNode[0], context, modulename);
+ resolvedType = context.Environment.MakeArrayType(arrType, (int)typeNode[1].Value);
+ return resolvedType;
+ }
+
+ private static IType ResolveTupleType(LNode typeNode, CompilerContext context, QualifiedName modulename)
+ {
+ IType resolvedType;
+ var tupleType = Utils.ResolveType(context.Binder, $"Tuple`{typeNode.ArgCount}", "System");
+
+ var tupleArgs = new List();
+ foreach (var garg in typeNode.Args)
+ {
+ tupleArgs.Add(ResolveTypeWithModule(garg, context, modulename));
+ }
+
+ resolvedType = tupleType.MakeGenericType(tupleArgs);
+ return resolvedType;
+ }
+
+ private static IType ResolveFunctionType(LNode typeNode, CompilerContext context, QualifiedName modulename, string func)
+ {
+ IType resolvedType;
+ var fnType = Utils.ResolveType(context.Binder, func, "System");
+
+ var funcArgs = new List();
+ foreach (var garg in typeNode.Args[2].Args)
+ {
+ funcArgs.Add(ResolveTypeWithModule(garg, context, modulename));
+ }
+
+ if (func.StartsWith("Func"))
+ {
+ funcArgs.Add(ResolveTypeWithModule(typeNode.Args[0], context, modulename));
+ }
+
+ resolvedType = fnType.MakeGenericType(funcArgs);
+ return resolvedType;
+ }
+
+ private static void ResolveUnitType(CompilerContext context, QualifiedName modulename, ref IType resolvedType, LNode unit)
+ {
+ if (unit is (_, (_, var u)))
+ {
+ var resolvedUnit = ResolveTypeWithModule(u, context, modulename);
+
+ if (!Utils.IsUnitType(context, resolvedUnit))
+ {
+ context.AddError(u, $"{resolvedUnit} is not a unit type");
+ }
+
+ resolvedType = new UnitType(resolvedType, resolvedUnit);
+ }
+ }
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Stages/EmitTreeStage.cs b/Source/Backlang.Driver/Compiling/Stages/EmitTreeStage.cs
index ef56151a..f331e26d 100644
--- a/Source/Backlang.Driver/Compiling/Stages/EmitTreeStage.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/EmitTreeStage.cs
@@ -6,24 +6,21 @@ public sealed class EmitTreeStage : IHandler
{
public async Task HandleAsync(CompilerContext context, Func> next)
{
- if (!context.Messages.Any())
- {
- var sb = new StringBuilder();
- var tree = context.Trees.FirstOrDefault();
-
- if (tree == null)
- {
- return context;
- }
+ var sb = new StringBuilder();
+ var tree = context.Trees.FirstOrDefault();
- foreach (var node in tree.Body)
- {
- sb.AppendLine(node.ToString());
- }
+ if (tree == null)
+ {
+ return context;
+ }
- File.WriteAllText(Path.Combine(context.TempOutputPath, context.OutputFilename + ".txt"), sb.ToString());
+ foreach (var node in tree.Body)
+ {
+ sb.AppendLine(node.ToString());
}
+ File.WriteAllText(Path.Combine(context.TempOutputPath, context.Options.OutputFilename + ".txt"), sb.ToString());
+
return await next.Invoke(context);
}
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Stages/ExpandingStages/ExpandMacrosStage.cs b/Source/Backlang.Driver/Compiling/Stages/ExpandingStages/ExpandMacrosStage.cs
index 5149a1c2..489fbd0a 100644
--- a/Source/Backlang.Driver/Compiling/Stages/ExpandingStages/ExpandMacrosStage.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/ExpandingStages/ExpandMacrosStage.cs
@@ -46,7 +46,7 @@ public async Task HandleAsync(CompilerContext context, Func HandleAsync(CompilerContext context, Func> next)
{
- foreach (var resource in context.EmbeddedResource)
+ foreach (var resource in context.Options.EmbeddedResource)
{
Stream strm = File.OpenRead(resource);
diff --git a/Source/Backlang.Driver/Compiling/Stages/InitStages/InitStage.TypeSystem.cs b/Source/Backlang.Driver/Compiling/Stages/InitStages/InitStage.TypeSystem.cs
index ea82a778..224596d3 100644
--- a/Source/Backlang.Driver/Compiling/Stages/InitStages/InitStage.TypeSystem.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/InitStages/InitStage.TypeSystem.cs
@@ -1,4 +1,5 @@
-using Backlang.Contracts.Scoping.Items;
+using Backlang.Codeanalysis.Core;
+using Backlang.Contracts.Scoping.Items;
using Backlang.Driver.Compiling.Targets.Dotnet;
using Flo;
using System.Collections.Concurrent;
@@ -21,19 +22,19 @@ public void InitTypeSystem(CompilerContext context)
InitPluginTargets(context.Plugins);
- if (string.IsNullOrEmpty(context.Target))
+ if (string.IsNullOrEmpty(context.Options.Target))
{
- context.Target = "dotnet";
+ context.Options.Target = "dotnet";
}
- if (context.OutputType == "dotnet")
+ if (context.Options.OutputType == "dotnet")
{
- context.OutputType = "Exe";
+ context.Options.OutputType = "Exe";
}
- if (_targets.ContainsKey(context.Target))
+ if (_targets.ContainsKey(context.Options.Target))
{
- var compilationTarget = _targets[context.Target];
+ var compilationTarget = _targets[context.Options.Target];
context.CompilationTarget = compilationTarget;
context.Environment = compilationTarget.Init(context);
@@ -49,21 +50,14 @@ public void InitTypeSystem(CompilerContext context)
}
else
{
- context.Messages.Add(Message.Error($"Target '{context.Target}' cannot be found"));
+ context.Messages.Add(Message.Error(new(ErrorID.TargetNotFound, context.Options.Target)));
return;
}
-
- var consoleType = context.Binder.ResolveTypes(new SimpleName("Console").Qualify("System")).FirstOrDefault();
-
- context.writeMethods = consoleType?.Methods.Where(
- method => (method.Name.ToString() == "Write" || method.Name.ToString() == "WriteLine")
- && method.IsStatic
- && method.ReturnParameter.Type == context.Environment.Void);
}
private static void AddIntrinsicType(CompilerContext context, Type type)
{
- var qualifier = Utils.QualifyNamespace(type.Namespace);
+ var qualifier = ConversionUtils.QualifyNamespace(type.Namespace);
var intrinsicAssembly = new DescribedAssembly(qualifier);
var instrinsicsType = new DescribedType(
diff --git a/Source/Backlang.Driver/Compiling/Stages/ParsingStage.cs b/Source/Backlang.Driver/Compiling/Stages/ParsingStage.cs
index 99afb022..2c8da970 100644
--- a/Source/Backlang.Driver/Compiling/Stages/ParsingStage.cs
+++ b/Source/Backlang.Driver/Compiling/Stages/ParsingStage.cs
@@ -6,14 +6,28 @@ public sealed class ParsingStage : IHandler
{
public async Task HandleAsync(CompilerContext context, Func> next)
{
- Parallel.ForEachAsync(context.InputFiles, (filename, ct) => {
+ if (context.Playground.IsPlayground)
+ {
+ var tree = CompilationUnit.FromText(context.Playground.Source);
+
+ ApplyTree(context, tree);
+
+ return await next.Invoke(context);
+ }
+
+ ParseSourceFiles(context);
+
+ return await next.Invoke(context);
+ }
+
+ private static void ParseSourceFiles(CompilerContext context)
+ {
+ Parallel.ForEachAsync(context.Options.InputFiles, (filename, ct) => {
if (File.Exists(filename))
{
var tree = CompilationUnit.FromFile(filename);
- context.Trees.Add(tree);
-
- context.Messages.AddRange(tree.Messages);
+ ApplyTree(context, tree);
}
else
{
@@ -22,7 +36,12 @@ public async Task HandleAsync(CompilerContext context, Func
+{
+ public async Task HandleAsync(CompilerContext context, Func> next)
+ {
+ while (!Debugger.IsAttached)
+ {
+ Thread.Sleep(1);
+ }
+
+ return await next.Invoke(context);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/ClrTypeEnvironmentBuilder.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/ClrTypeEnvironmentBuilder.cs
index 43b2d0c0..67aab8fa 100644
--- a/Source/Backlang.Driver/Compiling/Targets/Dotnet/ClrTypeEnvironmentBuilder.cs
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/ClrTypeEnvironmentBuilder.cs
@@ -19,7 +19,7 @@ public static IAssembly CollectTypes(Assembly ass)
{
if (!type.IsPublic) continue;
- var ns = Utils.QualifyNamespace(type.Namespace);
+ var ns = ConversionUtils.QualifyNamespace(type.Namespace);
var dt = new DescribedType(new SimpleName(type.Name).Qualify(ns), assembly);
dt.IsSealed = type.IsSealed;
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/DotNetAssembly.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/DotNetAssembly.cs
index 1a121a69..f141b494 100644
--- a/Source/Backlang.Driver/Compiling/Targets/Dotnet/DotNetAssembly.cs
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/DotNetAssembly.cs
@@ -1,9 +1,11 @@
using Backlang.Core.CompilerService;
+using Backlang.Driver.Compiling.Targets.Dotnet.RuntimeOptionsModels;
using Furesoft.Core.CodeDom.Compiler.Pipeline;
using Furesoft.Core.CodeDom.Compiler.TypeSystem;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System.Collections.Concurrent;
+using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
@@ -33,7 +35,7 @@ public DotNetAssembly(AssemblyContentDescription description)
_description = description;
- SetTargetFramework();
+ SetTargetFramework("net7.0"); //ToDo: get framework moniker from options
var console = typeof(Console).Assembly.GetName();
var core = typeof(UnitTypeAttribute).Assembly.GetName();
@@ -50,6 +52,8 @@ public void WriteTo(Stream output)
var clrType = new TypeDefinition(type.FullName.Slice(0, type.FullName.PathLength - 1).FullName.ToString(),
type.Name.ToString(), TypeAttributes.Class);
+ MakeStructReadonly(type, clrType);
+
_assemblyDefinition.MainModule.Types.Add(clrType);
typeMap.AddOrUpdate(type, (_) => clrType, (_, __) => clrType);
@@ -160,6 +164,22 @@ private static void ApplyStructLayout(TypeDefinition clrType, DescribedAttribute
}
}
+ private void MakeStructReadonly(DescribedType type, TypeDefinition clrType)
+ {
+ if (type.BaseTypes.Count > 0 && type.BaseTypes[0].FullName.ToString() == "System.ValueType")
+ {
+ clrType.IsSealed = true;
+
+ var readonlyCtor = typeof(ReadOnlyAttribute).GetConstructors()[0];
+
+ var ca = new CustomAttribute(_assemblyDefinition.MainModule.ImportReference(readonlyCtor));
+
+ ca.ConstructorArguments.Add(new(_assemblyDefinition.MainModule.ImportReference(typeof(bool)), true));
+
+ clrType.CustomAttributes.Add(ca);
+ }
+ }
+
private FieldDefinition GeneratePropertyField(DescribedProperty property)
{
var clrField = new FieldDefinition(@$"<{property.Name}>k__BackingField", FieldAttributes.Private, Resolve(property.PropertyType.FullName));
@@ -258,17 +278,17 @@ private void ConvertProperties(DescribedType type, TypeDefinition clrType)
private void AdjustBaseTypesAndInterfaces()
{
- foreach (var baseType in _needToAdjust)
+ foreach (var (definition, name) in _needToAdjust)
{
- var type = Resolve(baseType.name).Resolve();
+ var type = Resolve(name).Resolve();
if (type.IsInterface)
{
- baseType.definition.Interfaces.Add(new InterfaceImplementation(type));
+ definition.Interfaces.Add(new InterfaceImplementation(type));
}
else
{
- baseType.definition.BaseType = type;
+ definition.BaseType = type;
}
}
}
@@ -328,8 +348,7 @@ private void CompileBodys()
{
foreach (var bodyCompilation in _methodBodyCompilations)
{
- var variables =
- MethodBodyCompiler.Compile(bodyCompilation.DescribedMethod, bodyCompilation.ClrMethod, _assemblyDefinition, bodyCompilation.ClrType);
+ var variables = MethodBodyCompiler.Compile(bodyCompilation.DescribedMethod, bodyCompilation.ClrMethod, _assemblyDefinition, bodyCompilation.ClrType);
bodyCompilation.ClrMethod.DebugInformation.Scope =
new ScopeDebugInformation(bodyCompilation.ClrMethod.Body.Instructions[0],
@@ -539,9 +558,6 @@ private MethodDefinition GetMethodDefinition(DescribedBodyMethod m, IType return
private TypeReference Resolve(IType dtype)
{
- //ToDo: Only for debugging, remove if typecheck is done
- if (dtype == null) throw new Exception($"Type not found");
-
var resolvedType = Resolve(dtype.FullName);
if (resolvedType.HasGenericParameters)
{
@@ -572,13 +588,14 @@ private TypeReference Resolve(QualifiedName name)
return _assemblyDefinition.ImportType(name);
}
- private void SetTargetFramework()
+ private void SetTargetFramework(string moniker)
{
var tf = _assemblyDefinition.MainModule.ImportReference(typeof(TargetFrameworkAttribute).GetConstructors().First());
var item = new CustomAttribute(tf);
item.ConstructorArguments.Add(
- new CustomAttributeArgument(_assemblyDefinition.MainModule.ImportReference(typeof(string)), ".NETCoreApp,Version=v7.0"));
+ new CustomAttributeArgument(_assemblyDefinition.MainModule.ImportReference(typeof(string)),
+ $".NETCoreApp,Version=v{RuntimeConfig.GetVersion(moniker)}"));
_assemblyDefinition.CustomAttributes.Add(item);
}
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/DotNetTarget.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/DotNetTarget.cs
index 29001567..bfb0ed98 100644
--- a/Source/Backlang.Driver/Compiling/Targets/Dotnet/DotNetTarget.cs
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/DotNetTarget.cs
@@ -1,4 +1,5 @@
using Backlang.Core;
+using Backlang.Driver.Compiling.Targets.Dotnet.RuntimeOptionsModels;
using Furesoft.Core.CodeDom.Compiler.Pipeline;
using LeMP;
using System.Collections;
@@ -18,18 +19,13 @@ public class DotNetTarget : ICompilationTarget
public void AfterCompiling(CompilerContext context)
{
- var runtimeConfigStream = typeof(DotNetTarget).Assembly.GetManifestResourceStream("Backlang.Driver.compilation.runtimeconfig.json");
- var jsonStream = File.OpenWrite($"{Path.Combine(context.TempOutputPath, Path.GetFileNameWithoutExtension(context.OutputFilename))}.runtimeconfig.json");
-
- runtimeConfigStream.CopyTo(jsonStream);
-
- jsonStream.Close();
- runtimeConfigStream.Close();
+ RuntimeConfig.Save(context.TempOutputPath,
+ Path.GetFileNameWithoutExtension(context.Options.OutputFilename), context.Options);
}
public void BeforeCompiling(CompilerContext context)
{
- context.OutputFilename += ".dll";
+ context.Options.OutputFilename += ".dll";
}
public void BeforeExpandMacros(MacroProcessor processor)
@@ -69,7 +65,7 @@ public TypeEnvironment Init(CompilerContext context)
public void InitReferences(CompilerContext context)
{
- foreach (var r in context.References)
+ foreach (var r in context.Options.References)
{
AddFromAssembly(context, r);
}
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/ArithmetikEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/ArithmetikEmitter.cs
new file mode 100644
index 00000000..8b1650c0
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/ArithmetikEmitter.cs
@@ -0,0 +1,58 @@
+using Furesoft.Core.CodeDom.Compiler.Instructions;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+
+internal class ArithmetikEmitter : IEmitter
+{
+ private readonly ImmutableDictionary _stringOPMap = new Dictionary()
+ {
+ ["arith.+"] = OpCodes.Add,
+ ["arith.-"] = OpCodes.Sub,
+ ["arith.*"] = OpCodes.Mul,
+ ["arith./"] = OpCodes.Div,
+
+ ["arith.%"] = OpCodes.Div,
+
+ ["arith.&"] = OpCodes.And,
+ ["arith.|"] = OpCodes.Or,
+ ["arith.^"] = OpCodes.Xor,
+
+ ["arith.<"] = OpCodes.Clt,
+ ["arith.>"] = OpCodes.Cgt,
+ ["arith.=="] = OpCodes.Ceq,
+ }.ToImmutableDictionary();
+
+ public void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, Furesoft.Core.CodeDom.Compiler.Instruction instruction, BasicBlock block)
+ {
+ var arithProtype = (IntrinsicPrototype)instruction.Prototype;
+
+ if (_stringOPMap.ContainsKey(arithProtype.Name))
+ {
+ var op = _stringOPMap[arithProtype.Name];
+ ilProcessor.Emit(op); return;
+ }
+
+ switch (arithProtype.Name)
+ {
+ case "arith.!=":
+ ilProcessor.Emit(OpCodes.Ceq);
+ ilProcessor.Emit(OpCodes.Ldc_I4, 0);
+ ilProcessor.Emit(OpCodes.Ceq);
+ break;
+
+ case "arith.<=":
+ ilProcessor.Emit(OpCodes.Cgt);
+ ilProcessor.Emit(OpCodes.Ldc_I4, 0);
+ ilProcessor.Emit(OpCodes.Ceq);
+ break;
+
+ case "arith.>=":
+ ilProcessor.Emit(OpCodes.Clt);
+ ilProcessor.Emit(OpCodes.Ldc_I4, 0);
+ ilProcessor.Emit(OpCodes.Ceq);
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/CallEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/CallEmitter.cs
new file mode 100644
index 00000000..65fe668e
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/CallEmitter.cs
@@ -0,0 +1,50 @@
+using Furesoft.Core.CodeDom.Compiler.Instructions;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+
+internal class CallEmitter : IEmitter
+{
+ public void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor,
+ Furesoft.Core.CodeDom.Compiler.Instruction instruction, BasicBlock block)
+ {
+ var callPrototype = (CallPrototype)instruction.Prototype;
+
+ if (IntrinsicHelper.IsIntrinsicType(typeof(Intrinsics), callPrototype))
+ {
+ IntrinsicHelper.InvokeIntrinsic(typeof(Intrinsics), callPrototype.Callee, instruction, block);
+ return;
+ }
+
+ var method = MethodBodyCompiler.GetMethod(assemblyDefinition, callPrototype.Callee);
+
+ for (var i = 0; i < method.Parameters.Count; i++)
+ {
+ var valueType = block.Graph.NamedInstructions
+ .Where(_ => instruction.Arguments[i] == _.Tag)
+ .Select(_ => _.ResultType).FirstOrDefault();
+
+ var arg = method.Parameters[i];
+
+ //ToDo: move to IR
+ if (arg.ParameterType.FullName.ToString() == "System.Object")
+ {
+ ilProcessor.Emit(OpCodes.Box, assemblyDefinition.ImportType(valueType));
+ }
+ }
+
+ var op = OpCodes.Call;
+
+ if (!callPrototype.Callee.IsStatic)
+ {
+ op = OpCodes.Callvirt;
+ }
+
+ ilProcessor.Emit(op,
+ assemblyDefinition.MainModule.ImportReference(
+ method
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/CopyEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/CopyEmitter.cs
new file mode 100644
index 00000000..ec849e59
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/CopyEmitter.cs
@@ -0,0 +1,12 @@
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+
+public class CopyEmitter : IEmitter
+{
+ public void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, Furesoft.Core.CodeDom.Compiler.Instruction instruction, BasicBlock block)
+ {
+ ilProcessor.Emit(OpCodes.Dup);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/DynamicCastEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/DynamicCastEmitter.cs
new file mode 100644
index 00000000..3402e1ae
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/DynamicCastEmitter.cs
@@ -0,0 +1,16 @@
+using Furesoft.Core.CodeDom.Compiler.Instructions;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+
+internal class DynamicCastEmitter : IEmitter
+{
+ public void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, Furesoft.Core.CodeDom.Compiler.Instruction instruction, BasicBlock block)
+ {
+ var dcp = (DynamicCastPrototype)instruction.Prototype;
+ var checkType = assemblyDefinition.ImportType(dcp.TargetType.ElementType);
+
+ ilProcessor.Emit(OpCodes.Isinst, checkType);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/LoadEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/LoadEmitter.cs
new file mode 100644
index 00000000..41de7fe5
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/LoadEmitter.cs
@@ -0,0 +1,15 @@
+using Furesoft.Core.CodeDom.Compiler.Instructions;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+
+internal class LoadEmitter : IEmitter
+{
+ public void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, Furesoft.Core.CodeDom.Compiler.Instruction instruction, BasicBlock block)
+ {
+ var valueInstruction = block.Graph.GetInstruction(instruction.Arguments[0]);
+
+ MethodBodyCompiler.EmitConstant(ilProcessor, (ConstantPrototype)valueInstruction.Prototype);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/LoadIndirectEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/LoadIndirectEmitter.cs
new file mode 100644
index 00000000..ef631132
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/LoadIndirectEmitter.cs
@@ -0,0 +1,12 @@
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+
+internal class LoadIndirectEmitter : IEmitter
+{
+ public void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, Furesoft.Core.CodeDom.Compiler.Instruction instruction, BasicBlock block)
+ {
+ ilProcessor.Emit(OpCodes.Ldind_I4);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/NewArrayEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/NewArrayEmitter.cs
new file mode 100644
index 00000000..7a0e0e59
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/NewArrayEmitter.cs
@@ -0,0 +1,15 @@
+using Furesoft.Core.CodeDom.Compiler.Instructions;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+
+internal class NewArrayEmitter : IEmitter
+{
+ public void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, Furesoft.Core.CodeDom.Compiler.Instruction instruction, BasicBlock block)
+ {
+ var prototype = (AllocaArrayPrototype)instruction.Prototype;
+
+ ilProcessor.Emit(OpCodes.Newarr, assemblyDefinition.ImportType(prototype.ElementType));
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/NewObjectEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/NewObjectEmitter.cs
new file mode 100644
index 00000000..52b47279
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/NewObjectEmitter.cs
@@ -0,0 +1,16 @@
+using Furesoft.Core.CodeDom.Compiler.Instructions;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+
+internal class NewObjectEmitter : IEmitter
+{
+ public void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, Furesoft.Core.CodeDom.Compiler.Instruction instruction, BasicBlock block)
+ {
+ var newObjectPrototype = (NewObjectPrototype)instruction.Prototype;
+ var method = MethodBodyCompiler.GetMethod(assemblyDefinition, newObjectPrototype.Constructor);
+
+ ilProcessor.Emit(OpCodes.Newobj, method);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/TypeofEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/TypeofEmitter.cs
new file mode 100644
index 00000000..c220abda
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/Emitters/TypeofEmitter.cs
@@ -0,0 +1,16 @@
+using Backlang.Driver.Core.Instructions;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+
+internal class TypeofEmitter : IEmitter
+{
+ public void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor,
+ Furesoft.Core.CodeDom.Compiler.Instruction instruction, BasicBlock block)
+ {
+ var toip = (TypeOfInstructionPrototype)instruction.Prototype;
+
+ ilProcessor.Emit(OpCodes.Ldtoken, assemblyDefinition.ImportType(toip.Type));
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/IEmitter.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/IEmitter.cs
new file mode 100644
index 00000000..3759f324
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/IEmitter.cs
@@ -0,0 +1,11 @@
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Instruction = Furesoft.Core.CodeDom.Compiler.Instruction;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet;
+
+internal interface IEmitter
+{
+ void Emit(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor,
+ Instruction instruction, BasicBlock block);
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/MethodBodyCompiler.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/MethodBodyCompiler.cs
index 61aa11cd..19d82dc1 100644
--- a/Source/Backlang.Driver/Compiling/Targets/Dotnet/MethodBodyCompiler.cs
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/MethodBodyCompiler.cs
@@ -1,39 +1,34 @@
-using Backlang.Driver.Core.Instructions;
+using Backlang.Driver.Compiling.Targets.Dotnet.Emitters;
+using Backlang.Driver.Core.Instructions;
using Furesoft.Core.CodeDom.Compiler.Core.Constants;
using Furesoft.Core.CodeDom.Compiler.Flow;
using Furesoft.Core.CodeDom.Compiler.Instructions;
using Furesoft.Core.CodeDom.Compiler.TypeSystem;
using Mono.Cecil;
using Mono.Cecil.Cil;
+
using static Backlang.Driver.Compiling.Stages.CompilationStages.ImplementationStage;
using Instruction = Mono.Cecil.Cil.Instruction;
+using LoadFieldPrototype = Furesoft.Core.CodeDom.Compiler.Instructions.LoadFieldPrototype;
+using MethodDefinition = Mono.Cecil.MethodDefinition;
namespace Backlang.Driver.Compiling.Targets.Dotnet;
-internal class NothingFlow : BlockFlow
+public static class MethodBodyCompiler
{
- public override IReadOnlyList Instructions => throw new NotImplementedException();
-
- public override IReadOnlyList Branches => throw new NotImplementedException();
-
- public override InstructionBuilder GetInstructionBuilder(BasicBlockBuilder block, int instructionIndex)
- {
- throw new NotImplementedException();
- }
-
- public override BlockFlow WithBranches(IReadOnlyList branches)
- {
- throw new NotImplementedException();
- }
-
- public override BlockFlow WithInstructions(IReadOnlyList instructions)
+ private static readonly Dictionary _emitters = new()
{
- throw new NotImplementedException();
- }
-}
+ [typeof(CallPrototype)] = new CallEmitter(),
+ [typeof(TypeOfInstructionPrototype)] = new TypeofEmitter(),
+ [typeof(DynamicCastPrototype)] = new DynamicCastEmitter(),
+ [typeof(LoadIndirectPrototype)] = new LoadIndirectEmitter(),
+ [typeof(NewObjectPrototype)] = new NewObjectEmitter(),
+ [typeof(IntrinsicPrototype)] = new ArithmetikEmitter(),
+ [typeof(AllocaArrayPrototype)] = new NewArrayEmitter(),
+ [typeof(LoadPrototype)] = new LoadEmitter(),
+ [typeof(CopyPrototype)] = new CopyEmitter(),
+ };
-public static class MethodBodyCompiler
-{
public static Dictionary Compile(DescribedBodyMethod m, MethodDefinition clrMethod, AssemblyDefinition assemblyDefinition, TypeDefinition parentType)
{
var ilProcessor = clrMethod.Body.GetILProcessor();
@@ -58,6 +53,68 @@ public static Dictionary Compile(DescribedBodyMethod
return variables;
}
+ public static MethodReference GetMethod(AssemblyDefinition assemblyDefinition, IMethod method)
+ {
+ var parentType = assemblyDefinition.ImportType(method.ParentType).Resolve();
+
+ foreach (var m in parentType.Methods
+ .Where(_ => _.Name == method.Name.ToString()))
+ {
+ var parameters = m.Parameters;
+
+ if (parameters.Count == method.Parameters.Count)
+ {
+ if (method.GenericParameters.Any())
+ {
+ if (method.IsConstructor)
+ {
+ var dts = (DirectTypeSpecialization)GenericTypeMap.Cache[(method.FullName, method)];
+ var args = dts.GetRecursiveGenericArguments().Select(_ => assemblyDefinition.ImportType(_)).ToArray();
+ var genericType = assemblyDefinition.ImportType(dts);
+ var gctor = genericType.Resolve().Methods.FirstOrDefault(_ => _.Name == method.Name.ToString());
+
+ var mm = m.MakeHostInstanceGeneric(args);
+
+ return assemblyDefinition.MainModule.ImportReference(mm);
+ }
+
+ return m;
+ }
+
+ if (MatchesParameters(parameters, method))
+ return assemblyDefinition.MainModule.ImportReference(m);
+ }
+ }
+
+ return null;
+ }
+
+ public static void EmitConstant(ILProcessor ilProcessor, ConstantPrototype consProto)
+ {
+ dynamic v = consProto.Value;
+
+ if (v is StringConstant str)
+ {
+ ilProcessor.Emit(OpCodes.Ldstr, str.Value);
+ }
+ else if (v is Float32Constant f32)
+ {
+ ilProcessor.Emit(OpCodes.Ldc_R4, f32.Value);
+ }
+ else if (v is Float64Constant f64)
+ {
+ ilProcessor.Emit(OpCodes.Ldc_R8, f64.Value);
+ }
+ else if (v is NullConstant)
+ {
+ ilProcessor.Emit(OpCodes.Ldnull);
+ }
+ else if (v is IntegerConstant ic)
+ {
+ EmitIntegerConstant(ilProcessor, v, ic);
+ }
+ }
+
private static void FixJumps(ILProcessor ilProcessor, Dictionary labels, List<(int InstructionIndex, BasicBlockTag Target)> fixups)
{
foreach (var fixup in fixups)
@@ -81,69 +138,100 @@ private static void CompileBlock(BasicBlock block, AssemblyDefinition assemblyDe
{
var instruction = item.Instruction;
- if (instruction.Prototype is CallPrototype)
+ var prototypeType = instruction.Prototype.GetType();
+ if (_emitters.ContainsKey(prototypeType))
{
- EmitCall(assemblyDefinition, ilProcessor, instruction, block.Graph, block);
- }
- else if (instruction.Prototype is TypeOfInstructionPrototype toip)
- {
- ilProcessor.Emit(OpCodes.Ldtoken, assemblyDefinition.ImportType(toip.Type));
+ _emitters[prototypeType].Emit(assemblyDefinition, ilProcessor, instruction, block);
}
else if (instruction.Prototype is LoadLocalAPrototype lda)
{
var definition = variables[lda.Parameter.Name.ToString()];
ilProcessor.Emit(OpCodes.Ldloca_S, definition);
}
- else if (instruction.Prototype is LoadIndirectPrototype ldi)
- {
- ilProcessor.Emit(OpCodes.Ldind_I4);
- }
- else if (instruction.Prototype is NewObjectPrototype newObjectPrototype)
- {
- EmitNewObject(assemblyDefinition, ilProcessor, newObjectPrototype);
- }
- else if (instruction.Prototype is LoadPrototype)
- {
- var valueInstruction = block.Graph.GetInstruction(instruction.Arguments[0]);
- EmitConstant(assemblyDefinition, ilProcessor, (ConstantPrototype)valueInstruction.Prototype);
- }
else if (instruction.Prototype is AllocaPrototype allocA)
{
var variable = EmitVariableDeclaration(clrMethod, assemblyDefinition, ilProcessor, item, allocA);
variables.Add(item.Block.Parameters[variables.Count].Tag.Name, variable);
}
- else if (instruction.Prototype is AllocaArrayPrototype allocArray)
+ else if (instruction.Prototype is LoadArgPrototype larg)
{
- ilProcessor.Emit(OpCodes.Newarr, assemblyDefinition.ImportType(allocArray.ElementType));
+ if (item.NextInstructionOrNull?.Prototype is not StorePrototype)
+ {
+ EmitLoadArg(clrMethod, ilProcessor, parentType, larg);
+ }
}
- else if (instruction.Prototype is IntrinsicPrototype arith)
+ else if (instruction.Prototype is LoadLocalPrototype lloc)
{
- EmitArithmetic(ilProcessor, arith);
+ if (item.NextInstructionOrNull?.Prototype is not StorePrototype)
+ {
+ EmitLoadLocal(ilProcessor, lloc, variables);
+ }
}
- else if (instruction.Prototype is LoadArgPrototype larg)
+ else if (instruction.Prototype is LoadFieldPrototype fp)
{
- EmitLoadArg(clrMethod, ilProcessor, parentType, larg);
+ if (item.NextInstructionOrNull?.Prototype is not StorePrototype)
+ {
+ var type = assemblyDefinition.ImportType(fp.Field.ParentType).Resolve();
+ EmitLoadField(type, ilProcessor, fp);
+ }
}
- else if (instruction.Prototype is LoadLocalPrototype lloc)
+ else if (instruction.Prototype is GetFieldPointerPrototype fpa)
{
- EmitLoadLocal(ilProcessor, lloc, variables);
+ if (item.NextInstructionOrNull?.Prototype is not StorePrototype)
+ {
+ EmitLoadFieldA(parentType, ilProcessor, fpa);
+ }
}
- else if (instruction.Prototype is LoadFieldPrototype fp)
+ else if (instruction.Prototype is StorePrototype sp)
{
- EmitLoadField(parentType, ilProcessor, fp);
+ var ptr = sp.GetPointer(instruction);
+ var prototype = block.Graph.GetInstruction(ptr).Prototype;
+
+ if (prototype is LoadLocalPrototype lcp)
+ {
+ var definition = variables[lcp.Parameter.Name.ToString()];
+ ilProcessor.Emit(OpCodes.Stloc, definition);
+ }
+ else if (prototype is LoadFieldPrototype lfp)
+ {
+ var fieldType = assemblyDefinition.ImportType(lfp.Field.ParentType).Resolve();
+ var field = fieldType.Fields.FirstOrDefault(_ => _.Name == lfp.Field.Name.ToString());
+
+ ilProcessor.Emit(OpCodes.Stfld, field);
+ }
+ else if (prototype is GetFieldPointerPrototype lfap)
+ {
+ EmitLoadFieldA(parentType, ilProcessor, lfap);
+ }
+ else if (prototype is LoadArgPrototype largp)
+ {
+ var param = clrMethod.Parameters.FirstOrDefault(_ => _.Name == largp.Parameter.Name.ToString());
+
+ if (param != null)
+ {
+ var index = clrMethod.Parameters.IndexOf(param);
+
+ ilProcessor.Emit(OpCodes.Starg, index);
+ }
+ }
}
- else if (instruction.Prototype is StoreFieldPointerPrototype sp)
+ else if (instruction.Prototype is StoreFieldPointerPrototype spa)
{
- EmitStoreField(parentType, ilProcessor, sp);
+ EmitStoreField(parentType, ilProcessor, spa);
}
}
+ EmitBlockFlow(block, ilProcessor, clrMethod, fixups);
+ }
+
+ private static void EmitBlockFlow(BasicBlock block, ILProcessor ilProcessor, MethodDefinition clrMethod, List<(int InstructionIndex, BasicBlockTag Target)> fixups)
+ {
if (block.Flow is ReturnFlow rf)
{
if (rf.HasReturnValue)
{
- EmitConstant(assemblyDefinition, ilProcessor, (ConstantPrototype)rf.ReturnValue.Prototype);
+ EmitConstant(ilProcessor, (ConstantPrototype)rf.ReturnValue.Prototype);
}
ilProcessor.Emit(OpCodes.Ret);
@@ -156,21 +244,34 @@ private static void CompileBlock(BasicBlock block, AssemblyDefinition assemblyDe
else if (block.Flow is JumpConditionalFlow n)
{
fixups.Add((ilProcessor.Body.Instructions.Count, n.Branch.Target));
+
+ var op = OpCodes.Br;
+
+ var selector = (ConditionalJumpKind)n.ConditionSelector;
+ if (selector == ConditionalJumpKind.True)
+ {
+ op = OpCodes.Brtrue;
+ }
+ else if (selector == ConditionalJumpKind.False)
+ {
+ op = OpCodes.Brfalse;
+ }
+ else if (selector == ConditionalJumpKind.Equals)
+ {
+ op = OpCodes.Beq;
+ }
+ else if (selector == ConditionalJumpKind.NotEquals)
+ {
+ op = OpCodes.Bne_Un;
+ }
+
ilProcessor.Emit(
- (ConditionalJumpKind)n.ConditionSelector == ConditionalJumpKind.True ?
- OpCodes.Brtrue : OpCodes.Br, Instruction.Create(OpCodes.Nop)
+ op, Instruction.Create(OpCodes.Nop)
);
}
else if (block.Flow is UnreachableFlow)
{
- if (clrMethod.ReturnType.Name == "Void")
- {
- ilProcessor.Emit(OpCodes.Ret);
- }
- else
- {
- ilProcessor.Emit(OpCodes.Throw);
- }
+ ilProcessor.Emit(OpCodes.Throw);
}
}
@@ -194,6 +295,13 @@ private static void EmitLoadField(TypeDefinition parentType, ILProcessor ilProce
ilProcessor.Emit(OpCodes.Ldfld, field);
}
+ private static void EmitLoadFieldA(TypeDefinition parentType, ILProcessor ilProcessor, GetFieldPointerPrototype fp)
+ {
+ var field = parentType.Fields.FirstOrDefault(_ => _.Name == fp.Field.Name.ToString());
+
+ ilProcessor.Emit(OpCodes.Ldflda, field);
+ }
+
private static void EmitLoadArg(MethodDefinition clrMethod, ILProcessor ilProcessor, TypeReference parentType, LoadArgPrototype larg)
{
var param = clrMethod.Parameters.FirstOrDefault(_ => _.Name == larg.Parameter.Name.ToString());
@@ -208,175 +316,67 @@ private static void EmitLoadArg(MethodDefinition clrMethod, ILProcessor ilProces
}
else
{
- var thisPtr = larg.Parameter.Type.Name.ToString() == parentType.Name.ToString(); //ToDo: fix namespacing
-
- if (thisPtr)
+ if (larg.Parameter.Name.ToString() == "this")
{
ilProcessor.Emit(OpCodes.Ldarg_0);
}
}
}
- private static void EmitArithmetic(ILProcessor ilProcessor, IntrinsicPrototype arith)
+ private static void EmitIntegerConstant(ILProcessor ilProcessor, dynamic v, IntegerConstant ic)
{
- switch (arith.Name)
+ switch (ic.Spec.Size)
{
- case "arith.+":
- ilProcessor.Emit(OpCodes.Add); break;
- case "arith.-":
- ilProcessor.Emit(OpCodes.Sub); break;
- case "arith.*":
- ilProcessor.Emit(OpCodes.Mul); break;
- case "arith./":
- ilProcessor.Emit(OpCodes.Div); break;
- case "arith.%":
- ilProcessor.Emit(OpCodes.Rem); break;
- case "arith.&":
- ilProcessor.Emit(OpCodes.And); break;
- case "arith.|":
- ilProcessor.Emit(OpCodes.Or); break;
- case "arith.^":
- ilProcessor.Emit(OpCodes.Xor); break;
- case "arith.==":
- ilProcessor.Emit(OpCodes.Ceq); break;
- case "arith.!=":
- ilProcessor.Emit(OpCodes.Ceq);
- ilProcessor.Emit(OpCodes.Ldc_I4, 0);
- ilProcessor.Emit(OpCodes.Ceq);
+ case 1:
+ ilProcessor.Emit(!v.IsZero ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
break;
- case "arith.<":
- ilProcessor.Emit(OpCodes.Clt); break;
- case "arith.<=":
- ilProcessor.Emit(OpCodes.Cgt);
- ilProcessor.Emit(OpCodes.Ldc_I4, 0);
- ilProcessor.Emit(OpCodes.Ceq);
+ case 8:
+ if (ic.Spec.IsSigned)
+ {
+ ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToInt8());
+ }
+ else
+ {
+ ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToUInt8());
+ }
break;
- case "arith.>":
- ilProcessor.Emit(OpCodes.Cgt); break;
- case "arith.>=":
- ilProcessor.Emit(OpCodes.Clt);
- ilProcessor.Emit(OpCodes.Ldc_I4, 0);
- ilProcessor.Emit(OpCodes.Ceq);
+ case 16:
+ if (ic.Spec.IsSigned)
+ {
+ ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToInt16());
+ }
+ else
+ {
+ ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToUInt16());
+ }
break;
- }
- }
-
- private static void EmitNewObject(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, NewObjectPrototype newObjectPrototype)
- {
- var method = GetMethod(assemblyDefinition, newObjectPrototype.Constructor);
-
- ilProcessor.Emit(OpCodes.Newobj, method);
- }
-
- private static void EmitCall(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, Furesoft.Core.CodeDom.Compiler.Instruction instruction, FlowGraph implementation, BasicBlock block)
- {
- var callPrototype = (CallPrototype)instruction.Prototype;
-
- if (IntrinsicHelper.IsIntrinsicType(typeof(Intrinsics), callPrototype))
- {
- IntrinsicHelper.InvokeIntrinsic(typeof(Intrinsics), callPrototype.Callee, instruction, block);
- return;
- }
-
- var method = GetMethod(assemblyDefinition, callPrototype.Callee);
-
- for (var i = 0; i < method.Parameters.Count; i++)
- {
- var valueType = implementation.NamedInstructions
- .Where(_ => instruction.Arguments[i] == _.Tag)
- .Select(_ => _.ResultType).FirstOrDefault();
-
- var arg = method.Parameters[i];
- if (arg.ParameterType.FullName.ToString() == "System.Object")
- {
- ilProcessor.Emit(OpCodes.Box, assemblyDefinition.ImportType(valueType));
- }
- }
-
- ilProcessor.Emit(OpCodes.Call,
- assemblyDefinition.MainModule.ImportReference(
- method
- )
- );
- }
-
- private static void EmitConstant(AssemblyDefinition assemblyDefinition, ILProcessor ilProcessor, ConstantPrototype consProto)
- {
- dynamic v = consProto.Value;
-
- if (v is StringConstant str)
- {
- ilProcessor.Emit(OpCodes.Ldstr, str.Value);
- }
- else if (v is Float32Constant f32)
- {
- ilProcessor.Emit(OpCodes.Ldc_R4, f32.Value);
- }
- else if (v is Float64Constant f64)
- {
- ilProcessor.Emit(OpCodes.Ldc_R8, f64.Value);
- }
- else if (v is NullConstant)
- {
- ilProcessor.Emit(OpCodes.Ldnull);
- }
- else if (v is IntegerConstant ic)
- {
- switch (ic.Spec.Size)
- {
- case 1:
- ilProcessor.Emit(!v.IsZero ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
- break;
-
- case 8:
- if (ic.Spec.IsSigned)
- {
- ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToInt8());
- }
- else
- {
- ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToUInt8());
- }
- break;
-
- case 16:
- if (ic.Spec.IsSigned)
- {
- ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToInt16());
- }
- else
- {
- ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToUInt16());
- }
- break;
- case 32:
- if (ic.Spec.IsSigned)
- {
- ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToInt32());
- }
- else
- {
- ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToUInt32());
- }
- break;
+ case 32:
+ if (ic.Spec.IsSigned)
+ {
+ ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToInt32());
+ }
+ else
+ {
+ ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToUInt32());
+ }
+ break;
- case 64:
- if (ic.Spec.IsSigned)
- {
- ilProcessor.Emit(OpCodes.Ldc_I8, ic.ToInt64());
- }
- else
- {
- ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToUInt64());
- }
- break;
+ case 64:
+ if (ic.Spec.IsSigned)
+ {
+ ilProcessor.Emit(OpCodes.Ldc_I8, ic.ToInt64());
+ }
+ else
+ {
+ ilProcessor.Emit(OpCodes.Ldc_I4, ic.ToUInt64());
+ }
+ break;
- default:
- break;
- }
+ default:
+ break;
}
}
@@ -401,41 +401,6 @@ private static VariableDefinition EmitVariableDeclaration(MethodDefinition clrMe
return variable;
}
- private static MethodReference GetMethod(AssemblyDefinition assemblyDefinition, IMethod method)
- {
- var parentType = assemblyDefinition.ImportType(method.ParentType).Resolve();
-
- foreach (var m in parentType.Methods.Where(_ => _.Name == method.Name.ToString()))
- {
- var parameters = m.Parameters;
-
- if (parameters.Count == method.Parameters.Count)
- {
- if (method.GenericParameters.Any())
- {
- if (method.IsConstructor)
- {
- var dts = (DirectTypeSpecialization)GenericTypeMap.Cache[(method.FullName, method)];
- var args = dts.GetRecursiveGenericArguments().Select(_ => assemblyDefinition.ImportType(_)).ToArray();
- var genericType = assemblyDefinition.ImportType(dts);
- var gctor = genericType.Resolve().Methods.FirstOrDefault(_ => _.Name == method.Name.ToString());
-
- var mm = m.MakeHostInstanceGeneric(args);
-
- return assemblyDefinition.MainModule.ImportReference(mm);
- }
-
- return m;
- }
-
- if (MatchesParameters(parameters, method))
- return assemblyDefinition.MainModule.ImportReference(m);
- }
- }
-
- return null;
- }
-
private static bool MatchesParameters(Mono.Collections.Generic.Collection parameters, IMethod method)
{
//ToDo: refactor to improve code
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/RuntimeOptionsModels/FrameworkOptions.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/RuntimeOptionsModels/FrameworkOptions.cs
new file mode 100644
index 00000000..195fdb3e
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/RuntimeOptionsModels/FrameworkOptions.cs
@@ -0,0 +1,12 @@
+using Newtonsoft.Json;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.RuntimeOptionsModels;
+
+public class FrameworkOptions
+{
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("version")]
+ public string Version { get; set; }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/RuntimeOptionsModels/RuntimeConfig.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/RuntimeOptionsModels/RuntimeConfig.cs
new file mode 100644
index 00000000..b67bf667
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/RuntimeOptionsModels/RuntimeConfig.cs
@@ -0,0 +1,28 @@
+using Newtonsoft.Json;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.RuntimeOptionsModels;
+
+public class RuntimeConfig
+{
+ [JsonProperty("runtimeOptions")]
+ public RuntimeOptions RuntimeOptions { get; set; } = new();
+
+ public static void Save(string path, string name, CompilerCliOptions options)
+ {
+ path = Path.Combine(path, name + ".runtimeconfig.json");
+
+ var data = new RuntimeConfig();
+ data.RuntimeOptions.Tfm = options.TargetFramework;
+ data.RuntimeOptions.Framework.Name = "Microsoft.NETCore.App";
+ data.RuntimeOptions.Framework.Version = "7.0.0";
+
+ var json = JsonConvert.SerializeObject(data, Formatting.Indented);
+
+ File.WriteAllText(path, json);
+ }
+
+ public static string GetVersion(string frameworkMoniker)
+ {
+ return frameworkMoniker.Replace("net", "");
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Compiling/Targets/Dotnet/RuntimeOptionsModels/RuntimeOptions.cs b/Source/Backlang.Driver/Compiling/Targets/Dotnet/RuntimeOptionsModels/RuntimeOptions.cs
new file mode 100644
index 00000000..f2478478
--- /dev/null
+++ b/Source/Backlang.Driver/Compiling/Targets/Dotnet/RuntimeOptionsModels/RuntimeOptions.cs
@@ -0,0 +1,12 @@
+using Newtonsoft.Json;
+
+namespace Backlang.Driver.Compiling.Targets.Dotnet.RuntimeOptionsModels;
+
+public class RuntimeOptions
+{
+ [JsonProperty("tfm")]
+ public string Tfm { get; set; }
+
+ [JsonProperty("framework")]
+ public FrameworkOptions Framework { get; set; } = new();
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Branches.cs b/Source/Backlang.Driver/Core/Implementors/Branches.cs
new file mode 100644
index 00000000..08af9339
--- /dev/null
+++ b/Source/Backlang.Driver/Core/Implementors/Branches.cs
@@ -0,0 +1,7 @@
+namespace Backlang.Driver.Core.Implementors;
+
+public class BranchLabels
+{
+ public BasicBlockTag continueBranch;
+ public BasicBlockTag breakBranch;
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Expressions/ArrayExpressionImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Expressions/ArrayExpressionImplementor.cs
index 78082b77..04d5956e 100644
--- a/Source/Backlang.Driver/Core/Implementors/Expressions/ArrayExpressionImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Expressions/ArrayExpressionImplementor.cs
@@ -1,4 +1,6 @@
using Furesoft.Core.CodeDom.Compiler.Core.Constants;
+using Furesoft.Core.CodeDom.Compiler.Instructions;
+using System.Runtime.CompilerServices;
namespace Backlang.Driver.Core.Implementors.Expressions;
@@ -17,7 +19,41 @@ public NamedInstructionBuilder Handle(LNode node, BasicBlockBuilder block, IType
elementType = context.Binder.ResolveTypes(gn.TypeArgumentNames[0]).FirstOrDefault();
}
- //ToDo: add array initialisation
- return block.AppendInstruction(Instruction.CreateAllocaArray(elementType, counter));
+ var arrayValuesType = GetOrAddArrayValueType(context.Environment.MakeArrayType(elementType, 1), context, out var field); //Todo: replace rank
+
+ field.InitialValue = new byte[] { 1,2,3 };
+
+ //Todo: only emit this if values are primitive values otherwise emit storeelementref
+ var args = new List {
+ block.AppendInstruction(Instruction.CreateAllocaArray(elementType, counter)),
+ block.AppendInstruction(Instruction.CreateCopy(arrayValuesType, null))
+ };
+
+ var initArrayMethod = context.Binder.FindFunction("System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array, System.RuntimeFieldHandle)");
+
+ return block.AppendInstruction(Instruction.CreateCall(initArrayMethod, MethodLookup.Static, args));
+ }
+
+ private static DescribedType GetOrAddArrayValueType(IType elementType, CompilerContext context, out DescribedField field)
+ {
+ var arrayValuesType = (DescribedType)context.Binder.ResolveTypes(new SimpleName(Names.ArrayValues).Qualify("")).FirstOrDefault();
+
+ if (arrayValuesType == null)
+ {
+ arrayValuesType = new DescribedType(new SimpleName(Names.ArrayValues).Qualify(""), context.Assembly)
+ {
+ IsStatic = true
+ };
+
+ Utils.AddCompilerGeneratedAttribute(context.Binder, arrayValuesType);
+
+ context.Assembly.AddType(arrayValuesType);
+ }
+
+ var randomFieldName = Utils.GenerateIdentifier();
+ field = new DescribedField(arrayValuesType, new SimpleName(randomFieldName), true, elementType);
+
+ arrayValuesType.AddField(field);
+ return arrayValuesType;
}
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Expressions/AsExpressionImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Expressions/AsExpressionImplementor.cs
new file mode 100644
index 00000000..f3c04a90
--- /dev/null
+++ b/Source/Backlang.Driver/Core/Implementors/Expressions/AsExpressionImplementor.cs
@@ -0,0 +1,21 @@
+using static Backlang.Driver.Compiling.Stages.CompilationStages.ImplementationStage;
+
+namespace Backlang.Driver.Core.Implementors.Expressions;
+
+public class AsExpressionImplementor : IExpressionImplementor
+{
+ public bool CanHandle(LNode node) => node.ArgCount == 2 && node.Calls(CodeSymbols.As);
+
+ public NamedInstructionBuilder Handle(LNode node, BasicBlockBuilder block,
+ IType elementType, CompilerContext context, Scope scope, QualifiedName? modulename)
+ {
+ //ToDo: if type is obj and expr is valuetype -> box and vice versa unbox
+ var exprType = TypeDeducer.Deduce(node.Args[0], scope, context, modulename.Value);
+
+ AppendExpression(block, node.Args[0], exprType, context, scope, modulename);
+
+ var instr = Instruction.CreateDynamicCast(elementType.MakePointerType(PointerKind.Transient), null);
+
+ return block.AppendInstruction(instr);
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Expressions/BinaryExpressionImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Expressions/BinaryExpressionImplementor.cs
index a01aed5b..0547f90d 100644
--- a/Source/Backlang.Driver/Core/Implementors/Expressions/BinaryExpressionImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Expressions/BinaryExpressionImplementor.cs
@@ -5,10 +5,13 @@ namespace Backlang.Driver.Core.Implementors.Expressions;
public class BinaryExpressionImplementor : IExpressionImplementor
{
- public bool CanHandle(LNode node) => node.ArgCount == 2
- && !node.Calls(CodeSymbols.ColonColon)
- && !node.Calls(CodeSymbols.Tuple)
- && node.Name.Name.StartsWith("'");
+ public bool CanHandle(LNode node)
+ {
+ return node.ArgCount == 2
+ && !node.Calls(CodeSymbols.ColonColon)
+ && !node.Calls(CodeSymbols.Tuple)
+ && node.Name.Name.StartsWith("'");
+ }
public NamedInstructionBuilder Handle(LNode node, BasicBlockBuilder block,
IType elementType, CompilerContext context, Scope scope, QualifiedName? modulename)
@@ -21,10 +24,9 @@ public NamedInstructionBuilder Handle(LNode node, BasicBlockBuilder block,
if (leftType.TryGetOperator(node.Name.Name, out var opMethod, leftType, rightType))
{
- return block.AppendInstruction(
- Instruction.CreateCall(opMethod, MethodLookup.Static, new ValueTag[] { lhs, rhs }));
+ return block.AppendInstruction(Instruction.CreateCall(opMethod, MethodLookup.Static, new ValueTag[] { lhs, rhs }));
}
- else if (leftType == context.Environment.String || rightType == context.Environment.String)
+ else if (node.Calls(CodeSymbols.Add) && (leftType == context.Environment.String || rightType == context.Environment.String))
{
var concatMethods = context.Environment.String.Methods
.Where(_ => _.Name.ToString() == "Concat" && _.Parameters.Count == 2);
@@ -35,6 +37,7 @@ public NamedInstructionBuilder Handle(LNode node, BasicBlockBuilder block,
return block.AppendInstruction(call);
}
+ //ToDo: add check for unittype and no unitype. then unpack unit type
return block.AppendInstruction(Instruction.CreateBinaryArithmeticIntrinsic(node.Name.Name.Substring(1), false, elementType, lhs, rhs));
}
diff --git a/Source/Backlang.Driver/Core/Implementors/Expressions/CallExpressionEmitter.cs b/Source/Backlang.Driver/Core/Implementors/Expressions/CallExpressionEmitter.cs
index 37a7e1d6..2691cc9c 100644
--- a/Source/Backlang.Driver/Core/Implementors/Expressions/CallExpressionEmitter.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Expressions/CallExpressionEmitter.cs
@@ -9,17 +9,43 @@ public class CallExpressionEmitter : IExpressionImplementor
public NamedInstructionBuilder Handle(LNode node, BasicBlockBuilder block,
IType elementType, CompilerContext context, Scope scope, QualifiedName? modulename)
{
- if (node.Calls(CodeSymbols.New))
+ if (scope.TryGet(node.Name.Name, out var fn))
{
- //ToDo: append ctor
+ return ImplementationStage.AppendCall(context, block, node, fn.Overloads, scope, modulename, methodName: node.Name.Name);
}
- if (scope.TryGet(node.Name.Name, out var fn))
+ if (TryGetFreeFunctionsFromNamespace(context, node.Range.Source.FileName, out var functions))
{
- return ImplementationStage.AppendCall(context, block, node, fn.Overloads, scope, modulename, methodName: node.Name.Name);
+ return ImplementationStage.AppendCall(context, block, node, functions, scope, modulename, methodName: node.Name.Name);
}
context.AddError(node, $"function {node.Name.Name} not found");
return null;
}
+
+ private static bool TryGetFreeFunctionsFromNamespace(CompilerContext context, string filename, out IEnumerable functions)
+ {
+ var allFreeFunctions = new List();
+ if (context.FileScope.ImportetNamespaces.TryGetValue(filename, out var importedNamespaces))
+ {
+ foreach (var ns in importedNamespaces.ImportedNamespaces)
+ {
+ if (context.Binder.TryResolveNamespace(ns, out var resolvedNs))
+ {
+ if (!resolvedNs.Types.Any(_ => _.Name.ToString() == Names.FreeFunctions))
+ {
+ continue;
+ }
+
+ allFreeFunctions.AddRange(resolvedNs.Types.First(_ => _.Name.ToString() == Names.FreeFunctions).Methods);
+ }
+ }
+
+ functions = allFreeFunctions;
+ return true;
+ }
+
+ functions = null;
+ return false;
+ }
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Expressions/IdentifierExpressionImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Expressions/IdentifierExpressionImplementor.cs
index c2ebf6f6..de97483e 100644
--- a/Source/Backlang.Driver/Core/Implementors/Expressions/IdentifierExpressionImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Expressions/IdentifierExpressionImplementor.cs
@@ -9,14 +9,17 @@ public class IdentifierExpressionImplementor : IExpressionImplementor
public NamedInstructionBuilder Handle(LNode node, BasicBlockBuilder block,
IType elementType, CompilerContext context, Scope scope, QualifiedName? modulename)
{
- scope.TryGet(node.Name.Name, out var item);
+ if (!scope.TryGet(node.Name.Name, out var item))
+ {
+ context.AddError(node, new(Codeanalysis.Core.ErrorID.NotDefined, node.Name.Name));
+ return null;
+ }
if (item is ParameterScopeItem psi)
{
return block.AppendInstruction(Instruction.CreateLoadArg(psi.Parameter));
}
-
- if (item is VariableScopeItem vsi)
+ else if (item is VariableScopeItem vsi)
{
return block.AppendInstruction(Instruction.CreateLoadLocal(vsi.Parameter));
}
diff --git a/Source/Backlang.Driver/Core/Implementors/Expressions/MemberExpressionImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Expressions/MemberExpressionImplementor.cs
new file mode 100644
index 00000000..ed4116b4
--- /dev/null
+++ b/Source/Backlang.Driver/Core/Implementors/Expressions/MemberExpressionImplementor.cs
@@ -0,0 +1,42 @@
+using Backlang.Contracts.Scoping.Items;
+using Furesoft.Core.CodeDom.Compiler.Instructions;
+
+namespace Backlang.Driver.Core.Implementors.Expressions;
+
+public class MemberExpressionImplementor : IExpressionImplementor
+{
+ public bool CanHandle(LNode node) => node.ArgCount == 2
+ && !node.Calls(CodeSymbols.ColonColon)
+ && !node.Calls(CodeSymbols.Tuple)
+ && node.Name.Name.StartsWith("'.");
+
+ public NamedInstructionBuilder Handle(LNode node, BasicBlockBuilder block,
+ IType elementType, CompilerContext context, Scope scope, QualifiedName? modulename)
+ {
+ scope.TryGet(node.Args[0].Name.Name, out var item);
+
+ var type = TypeDeducer.Deduce(node.Args[0], scope, context, modulename.Value);
+
+ var field = type.Fields.FirstOrDefault(_ => _.Name.ToString() == node.Args[1].Name.ToString());
+ if (field != null)
+ {
+ block.AppendInstruction(Instruction.CreateLoadLocal(item.Parameter));
+ return block.AppendInstruction(Instruction.CreateLoadField(field));
+ }
+
+ var method = type.Methods.FirstOrDefault(_ => _.Name.ToString() == node.Args[1].Name.ToString());
+ if (method != null)
+ {
+ var instance = ImplementationStage.AppendExpression(block, node[0], type, context, scope, modulename);
+
+ var callTags = ImplementationStage.AppendCallArguments(context, block, node[1], scope, modulename);
+ callTags.Insert(0, instance);
+
+ var call = Instruction.CreateCall(method, MethodLookup.Virtual, callTags);
+
+ return block.AppendInstruction(call);
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/IStatementImplementor.cs b/Source/Backlang.Driver/Core/Implementors/IStatementImplementor.cs
index 7445cb92..d1a4d747 100644
--- a/Source/Backlang.Driver/Core/Implementors/IStatementImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/IStatementImplementor.cs
@@ -2,6 +2,5 @@
public interface IStatementImplementor
{
- BasicBlockBuilder Implement(CompilerContext context, IMethod method,
- BasicBlockBuilder block, LNode node, QualifiedName? modulename, Scope scope);
+ BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null);
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/AssignmentImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/AssignmentImplementor.cs
index 219fc758..071c2267 100644
--- a/Source/Backlang.Driver/Core/Implementors/Statements/AssignmentImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/AssignmentImplementor.cs
@@ -5,7 +5,7 @@ namespace Backlang.Driver.Core.Implementors.Statements;
public class AssignmentImplementor : IStatementImplementor
{
- public BasicBlockBuilder Implement(CompilerContext context, IMethod method, BasicBlockBuilder block, LNode node, QualifiedName? modulename, Scope scope)
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
{
if (node is (_, var left, var right))
{
@@ -20,9 +20,11 @@ public BasicBlockBuilder Implement(CompilerContext context, IMethod method, Basi
context.AddError(node, $"Cannot assing immutable variable '{va.Name}'");
}
- var value = AppendExpression(block, right, rt, context, scope, modulename.Value);
+ var value = AppendExpression(block, right, rt, context,
+ scope, modulename.Value);
+ var pointer = block.AppendInstruction(Instruction.CreateLoadLocal(va.Parameter));
- block.AppendInstruction(Instruction.CreateStore(lt, new ValueTag(va.Parameter.Name.ToString()), value));
+ block.AppendInstruction(Instruction.CreateStore(lt, pointer, value));
}
else if (left is ("'.", var t, var c))
{
@@ -32,8 +34,11 @@ public BasicBlockBuilder Implement(CompilerContext context, IMethod method, Basi
if (field != null)
{
+ block.AppendInstruction(Instruction.CreateLoadLocalAdress(vsi.Parameter));
+ var value = AppendExpression(block, right, field.FieldType,
+ context, scope, modulename.Value);
+
var pointer = block.AppendInstruction(Instruction.CreateLoadField(field));
- var value = AppendExpression(block, right, field.FieldType, context, scope, modulename.Value);
block.AppendInstruction(Instruction.CreateStore(field.FieldType, pointer, value));
}
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/BreakStatementImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/BreakStatementImplementor.cs
new file mode 100644
index 00000000..a3a5459e
--- /dev/null
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/BreakStatementImplementor.cs
@@ -0,0 +1,13 @@
+using Furesoft.Core.CodeDom.Compiler.Flow;
+
+namespace Backlang.Driver.Core.Implementors.Statements;
+
+public class BreakStatementImplementor : IStatementImplementor
+{
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
+ {
+ block.Flow = new JumpFlow(branchLabels.breakBranch);
+
+ return block;
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/CallImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/CallImplementor.cs
index 0195f117..3a3b1865 100644
--- a/Source/Backlang.Driver/Core/Implementors/Statements/CallImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/CallImplementor.cs
@@ -1,12 +1,21 @@
using Backlang.Contracts.Scoping.Items;
+using Backlang.Driver.Core.Instructions;
using static Backlang.Driver.Compiling.Stages.CompilationStages.ImplementationStage;
namespace Backlang.Driver.Core.Implementors.Statements;
public class CallImplementor : IStatementImplementor
{
- public BasicBlockBuilder Implement(CompilerContext context, IMethod method, BasicBlockBuilder block,
- LNode node, QualifiedName? modulename, Scope scope)
+ public static void AppendDiscardReturnValue(BasicBlockBuilder block, IType type)
+ {
+ if (type.FullName.ToString() != "System.Void")
+ {
+ //Discard value if its not been stored anywhere
+ block.AppendInstruction(new PopInstructionPrototype().Instantiate(new List()));
+ }
+ }
+
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
{
if (node is ("'.", var target, var callee) && target is ("this", _))
{
@@ -18,11 +27,14 @@ public BasicBlockBuilder Implement(CompilerContext context, IMethod method, Basi
if (scope.TryGet(callee.Name.Name, out var fsi))
{
- AppendCall(context, block, callee, fsi.Overloads, scope, modulename);
+ AppendCall(context, block, callee, fsi.Overloads,
+ scope, modulename);
+
+ AppendDiscardReturnValue(block, fsi.Overloads[0].ReturnParameter.Type);
}
else
{
- context.AddError(node, $"Cannot find function '{callee.Name.Name}'");
+ context.AddError(node, new(Codeanalysis.Core.ErrorID.CannotFindFunction, callee.Name.Name));
}
}
else
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/ContinueStatementImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/ContinueStatementImplementor.cs
new file mode 100644
index 00000000..2828335c
--- /dev/null
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/ContinueStatementImplementor.cs
@@ -0,0 +1,13 @@
+using Furesoft.Core.CodeDom.Compiler.Flow;
+
+namespace Backlang.Driver.Core.Implementors.Statements;
+
+public class ContinueStatementImplementor : IStatementImplementor
+{
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
+ {
+ block.Flow = new JumpFlow(branchLabels.continueBranch);
+
+ return block;
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/DoWhileImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/DoWhileImplementor.cs
new file mode 100644
index 00000000..a9ab0853
--- /dev/null
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/DoWhileImplementor.cs
@@ -0,0 +1,37 @@
+using Furesoft.Core.CodeDom.Compiler.Flow;
+using static Backlang.Driver.Compiling.Stages.CompilationStages.ImplementationStage;
+
+namespace Backlang.Driver.Core.Implementors.Statements;
+
+public class DoWhileImplementor : IStatementImplementor
+{
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
+ {
+ if (node is (_, var body, var condition))
+ {
+ TypeDeducer.ExpectType(condition, scope, context,
+ modulename.Value, context.Environment.Boolean);
+
+ var do_body = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("do_start"));
+ var do_condition = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("do_body"));
+ var do_after = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("do_after"));
+
+ do_after.Flow = new NothingFlow();
+ do_body.Flow = new NothingFlow();
+
+ branchLabels.breakBranch = do_after;
+ branchLabels.continueBranch = do_body;
+
+ AppendBlock(body, do_body, context, method, modulename, scope.CreateChildScope(), branchLabels);
+
+ AppendExpression(do_condition, condition, context.Environment.Boolean,
+ context, scope.CreateChildScope(), modulename);
+
+ do_condition.Flow = new JumpConditionalFlow(do_body, ConditionalJumpKind.True);
+
+ return do_after;
+ }
+
+ return block;
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/IfImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/IfImplementor.cs
index e1997b15..a18785c5 100644
--- a/Source/Backlang.Driver/Core/Implementors/Statements/IfImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/IfImplementor.cs
@@ -5,41 +5,74 @@ namespace Backlang.Driver.Core.Implementors.Statements;
public class IfImplementor : IStatementImplementor
{
- public BasicBlockBuilder Implement(CompilerContext context, IMethod method, BasicBlockBuilder block,
- LNode node, QualifiedName? modulename, Scope scope)
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
{
- if (node is (_, (_, var condition, var body, var el)))
+ if (node is (_, (_, var condition, var body, var elseBody)))
{
- TypeDeducer.ExpectType(condition, scope, context, modulename.Value, context.Environment.Boolean);
+ TypeDeducer.ExpectType(condition, scope, context, modulename.Value,
+ context.Environment.Boolean);
- var ifBlock = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("if"));
- AppendBlock(body, ifBlock, context, method, modulename, scope.CreateChildScope());
+ var if_after = ImplementIf(block, context, method, modulename, scope, branchLabels, condition, body);
- if (el != LNode.Missing)
+ if (elseBody.Name != LNode.Missing.Name)
{
- var elseBlock = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("else"));
- AppendBlock(el, elseBlock, context, method, modulename, scope.CreateChildScope());
+ if_after = ImplementIf(if_after, context, method, modulename, scope, branchLabels, condition, elseBody, true);
}
- var if_condition = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("if_condition"));
- if (condition.Calls(CodeSymbols.Bool))
- {
- if_condition.Flow = new JumpConditionalFlow(ifBlock, ConditionalJumpKind.True);
- }
- else
- {
- AppendExpression(if_condition, condition, context.Environment.Boolean, context, scope, modulename);
- if_condition.Flow = new JumpConditionalFlow(ifBlock, ConditionalJumpKind.Equals);
- }
+ return if_after;
+ }
+
+ return null;
+ }
+
+ private static BasicBlockBuilder ImplementIf(BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename,
+ Scope scope, BranchLabels branchLabels, LNode condition, LNode body, bool negate = false)
+ {
+ var if_start = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("if_start"));
+ var if_condition = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("if_condition"));
+ var if_end = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("if_end"));
+
+ AppendBlock(body, if_start, context, method, modulename, scope.CreateChildScope(), branchLabels);
+
+ AppendExpression(if_condition, condition, context.Environment.Boolean, context, scope, modulename);
+
+ if_condition.Flow = new JumpConditionalFlow(if_start, negate ? ConditionalJumpKind.False : ConditionalJumpKind.True);
- block.Flow = new JumpFlow(if_condition);
+ block.Flow = new JumpFlow(if_condition);
- var after = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("after"));
- ifBlock.Flow = new JumpFlow(after);
+ if_end.Flow = new NothingFlow();
- return after;
+ var if_after = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("if_after"));
+ if_after.Flow = new NothingFlow();
+
+ return if_after;
+ }
+
+ private static BasicBlockBuilder ImplementIfElse(BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename,
+ Scope scope, BranchLabels branchLabels, LNode condition, LNode body, LNode elseBody)
+ {
+ var if_condition = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("if_condition"));
+ var if_body = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("if_start"));
+ var else_end = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("else_end"));
+ var else_body = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("else_start"));
+
+ else_end.Flow = new NothingFlow();
+
+ AppendExpression(if_condition, condition, context.Environment.Boolean, context, scope, modulename);
+ if_condition.Flow = new JumpConditionalFlow(else_body, ConditionalJumpKind.False);
+
+ AppendBlock(body, if_body, context, method, modulename, scope.CreateChildScope(), branchLabels);
+ AppendBlock(elseBody, else_body, context, method, modulename, scope.CreateChildScope(), branchLabels);
+
+ if (if_body.Flow is NothingFlow)
+ {
+ if_body.Flow = new JumpFlow(else_end);
+ }
+ if (else_body.Flow is NothingFlow)
+ {
+ else_body.Flow = new JumpFlow(else_end);
}
- return null;
+ return else_end;
}
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/PrintOrPrintlnImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/PrintOrPrintlnImplementor.cs
new file mode 100644
index 00000000..b29c0f40
--- /dev/null
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/PrintOrPrintlnImplementor.cs
@@ -0,0 +1,18 @@
+namespace Backlang.Driver.Core.Implementors.Statements;
+
+public class PrintOrPrintlnImplementor : IStatementImplementor
+{
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
+ {
+ var deducedArg = TypeDeducer.Deduce(node.Args[0], scope,
+ context, modulename.Value);
+ var functionName = node.Calls("println") ? "WriteLine" : "Write";
+
+ var printFunction = context.Binder.FindFunction($"System.Console::{functionName}({deducedArg})");
+
+ ImplementationStage.AppendCall(context, block, node,
+ printFunction, scope, modulename.Value);
+
+ return block;
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/ReturnImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/ReturnImplementor.cs
index 9d69e39f..79c4e940 100644
--- a/Source/Backlang.Driver/Core/Implementors/Statements/ReturnImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/ReturnImplementor.cs
@@ -5,15 +5,15 @@ namespace Backlang.Driver.Core.Implementors.Statements;
public class ReturnImplementor : IStatementImplementor
{
- public BasicBlockBuilder Implement(CompilerContext context, IMethod method, BasicBlockBuilder block,
- LNode node, QualifiedName? modulename, Scope scope)
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
{
if (node.ArgCount == 1)
{
var valueNode = node.Args[0];
AppendExpression(block, valueNode,
- TypeDeducer.Deduce(valueNode, scope, context, modulename.Value), context, scope, modulename);
+ TypeDeducer.Deduce(valueNode, scope, context, modulename.Value),
+ context, scope, modulename);
block.Flow = new ReturnFlow();
}
@@ -21,6 +21,7 @@ public BasicBlockBuilder Implement(CompilerContext context, IMethod method, Basi
{
block.Flow = new ReturnFlow();
}
+
return block;
}
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/StaticCallImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/StaticCallImplementor.cs
index 06594fb2..00de84f8 100644
--- a/Source/Backlang.Driver/Core/Implementors/Statements/StaticCallImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/StaticCallImplementor.cs
@@ -14,10 +14,11 @@ public NamedInstructionBuilder Handle(LNode node, BasicBlockBuilder block,
return ImplementationStage.AppendCall(context, block, callee, type.Methods, scope, modulename, methodName: callee.Name.Name);
}
- public BasicBlockBuilder Implement(CompilerContext context, IMethod method, BasicBlockBuilder block,
- LNode node, QualifiedName? modulename, Scope scope)
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
{
- Handle(node, block, TypeDeducer.Deduce(node, scope, context, modulename.Value), context, scope, modulename);
+ Handle(node, block,
+ TypeDeducer.Deduce(node, scope, context, modulename.Value),
+ context, scope, modulename);
return block;
}
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/ThrowImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/ThrowImplementor.cs
index 88eca0a1..4738513b 100644
--- a/Source/Backlang.Driver/Core/Implementors/Statements/ThrowImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/ThrowImplementor.cs
@@ -5,15 +5,16 @@ namespace Backlang.Driver.Core.Implementors.Statements;
public class ThrowImplementor : IStatementImplementor
{
- public BasicBlockBuilder Implement(CompilerContext context, IMethod method, BasicBlockBuilder block,
- LNode node, QualifiedName? modulename, Scope scope)
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
{
var valueNode = node.Args[0].Args[0];
var constant = block.AppendInstruction(ConvertConstant(
- GetLiteralType(valueNode, context, scope, modulename.Value), valueNode.Value));
+ GetLiteralType(valueNode, context, scope,
+ modulename.Value), valueNode.Value));
var msg = block.AppendInstruction(
- Instruction.CreateLoad(GetLiteralType(valueNode, context, scope, modulename.Value), constant));
+ Instruction.CreateLoad(GetLiteralType(valueNode, context,
+ scope, modulename.Value), constant));
if (node.Args[0].Name.Name == "#string")
{
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/VariableImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/VariableImplementor.cs
index b97572a4..8df43f8c 100644
--- a/Source/Backlang.Driver/Core/Implementors/Statements/VariableImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/VariableImplementor.cs
@@ -1,20 +1,22 @@
-using Backlang.Contracts.Scoping.Items;
+using Backlang.Codeanalysis.Core;
+using Backlang.Contracts.Scoping.Items;
using Backlang.Contracts.TypeSystem;
namespace Backlang.Driver.Core.Implementors.Statements;
public class VariableImplementor : IStatementImplementor
{
- public BasicBlockBuilder Implement(CompilerContext context, IMethod method, BasicBlockBuilder block,
- LNode node, QualifiedName? modulename, Scope scope)
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels = null)
{
var decl = node.Args[1];
var typename = ConversionUtils.GetQualifiedName(node.Args[0]);
- var elementType = TypeInheritanceStage.ResolveTypeWithModule(node.Args[0], context, modulename.Value, typename);
+ var elementType = TypeInheritanceStage.ResolveTypeWithModule(node.Args[0],
+ context, modulename.Value, typename);
- var deducedValueType = TypeDeducer.Deduce(decl.Args[1], scope, context, modulename.Value);
+ var deducedValueType = TypeDeducer.Deduce(decl.Args[1], scope,
+ context, modulename.Value);
if (elementType == null)
{
@@ -24,24 +26,28 @@ public BasicBlockBuilder Implement(CompilerContext context, IMethod method, Basi
{
if (node.Args[0] is (_, (_, var tp))) //ToDo: Implement Helper function To Get Typename
{
- context.AddError(node, $"{tp.Name} cannot be resolved");
+ context.AddError(node,
+ new(ErrorID.CannotBeResolved, tp.Name.ToString()));
}
}
}
else
{
- if (deducedValueType != null && !elementType.IsAssignableTo(deducedValueType) && deducedValueType != context.Environment.Void)
+ if (deducedValueType != null && !elementType.IsAssignableTo(deducedValueType) &&
+ deducedValueType != context.Environment.Void)
{
if (elementType is UnitType ut)
{
if (ut != deducedValueType)
{
- context.AddError(node, $"Unit Type mismatch {elementType} {deducedValueType}");
+ context.AddError(node,
+ new(ErrorID.UnitTypeMismatch, elementType.ToString(), deducedValueType.ToString()));
}
return block;
}
- context.AddError(node, $"Type mismatch {elementType} {deducedValueType}");
+ context.AddError(node,
+ new(ErrorID.TypeMismatch, elementType.ToString(), deducedValueType.ToString()));
}
}
@@ -59,12 +65,13 @@ public BasicBlockBuilder Implement(CompilerContext context, IMethod method, Basi
}
else
{
- context.AddError(decl.Args[0], $"{varname} already declared");
+ context.AddError(decl.Args[0], new(ErrorID.AlreadyDeclared, varname));
}
if (deducedValueType == null) return block;
- ImplementationStage.AppendExpression(block, decl.Args[1], elementType, context, scope, modulename);
+ ImplementationStage.AppendExpression(block, decl.Args[1], elementType, context,
+ scope, modulename);
block.AppendInstruction(Instruction.CreateAlloca(elementType));
diff --git a/Source/Backlang.Driver/Core/Implementors/Statements/WhileImplementor.cs b/Source/Backlang.Driver/Core/Implementors/Statements/WhileImplementor.cs
index 1dcb4620..61b51389 100644
--- a/Source/Backlang.Driver/Core/Implementors/Statements/WhileImplementor.cs
+++ b/Source/Backlang.Driver/Core/Implementors/Statements/WhileImplementor.cs
@@ -1,45 +1,40 @@
-using Backlang.Driver.Compiling.Targets.Dotnet;
-using Furesoft.Core.CodeDom.Compiler.Flow;
+using Furesoft.Core.CodeDom.Compiler.Flow;
using static Backlang.Driver.Compiling.Stages.CompilationStages.ImplementationStage;
namespace Backlang.Driver.Core.Implementors.Statements;
public class WhileImplementor : IStatementImplementor
{
- public BasicBlockBuilder Implement(CompilerContext context, IMethod method, BasicBlockBuilder block,
- LNode node, QualifiedName? modulename, Scope scope)
+ public BasicBlockBuilder Implement(LNode node, BasicBlockBuilder block, CompilerContext context, IMethod method, QualifiedName? modulename, Scope scope, BranchLabels branchLabels)
{
if (node is (_, var condition, var body))
{
- TypeDeducer.ExpectType(condition, scope, context, modulename.Value, context.Environment.Boolean);
+ TypeDeducer.ExpectType(condition, scope, context, modulename.Value,
+ context.Environment.Boolean);
var while_start = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("while_start"));
- AppendBlock(body, while_start, context, method, modulename, scope.CreateChildScope());
-
var while_condition = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("while_condition"));
- AppendExpression(block, condition, context.Environment.Boolean, context, scope, modulename);
- //while_condition.Flow = new JumpFlow(while_start);
- while_condition.Flow = new NothingFlow();
-
var while_end = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("while_end"));
- block.Flow = new JumpFlow(while_condition);
- //block.Flow = new NothingFlow();
+ var while_after = block.Graph.AddBasicBlock(LabelGenerator.NewLabel("while_after"));
+ while_after.Flow = new NothingFlow();
- while_start.Flow = new NothingFlow();
-
- if (condition.Calls(CodeSymbols.Bool))
- {
- while_end.Flow = new JumpConditionalFlow(while_start, ConditionalJumpKind.True);
- }
- else
+ branchLabels = new()
{
- //AppendExpression(block, condition, method.ParentType, context, scope, modulename);
- while_end.Flow = new NothingFlow();
- }
+ breakBranch = while_after,
+ continueBranch = while_condition
+ };
+
+ AppendBlock(body, while_start, context, method, modulename, scope.CreateChildScope(), branchLabels);
+
+ AppendExpression(while_condition, condition, context.Environment.Boolean, context, scope, modulename);
+
+ while_condition.Flow = new JumpConditionalFlow(while_start, ConditionalJumpKind.True);
+
+ block.Flow = new JumpFlow(while_condition);
- // while_end.Flow = new NothingFlow();
+ while_end.Flow = new NothingFlow();
- return block.Graph.AddBasicBlock();
+ return while_after;
}
return null;
diff --git a/Source/Backlang.Driver/Core/ImplicitTypeCastTable.cs b/Source/Backlang.Driver/Core/ImplicitTypeCastTable.cs
index 891545fd..122986a8 100644
--- a/Source/Backlang.Driver/Core/ImplicitTypeCastTable.cs
+++ b/Source/Backlang.Driver/Core/ImplicitTypeCastTable.cs
@@ -12,9 +12,9 @@ public static void InitCastMap(TypeEnvironment environment)
castMap.Add(environment.UInt16, new[] { environment.UInt32, environment.UInt64 });
castMap.Add(environment.UInt32, new[] { environment.UInt64 });
- castMap.Add(environment.Int8, new[] { environment.Int16, environment.Int32, environment.Int64 });
- castMap.Add(environment.Int16, new[] { environment.Int32, environment.Int64 });
- castMap.Add(environment.Int32, new[] { environment.Int64 });
+ castMap.Add(environment.Int8, new[] { environment.Int16, environment.Int32, environment.Int64, environment.Float32 });
+ castMap.Add(environment.Int16, new[] { environment.Int32, environment.Int64, environment.Float32, environment.Float64 });
+ castMap.Add(environment.Int32, new[] { environment.Int64, environment.Float64 });
}
public static bool IsAssignableTo(this IType type, IType toCast)
diff --git a/Source/Backlang.Driver/Core/Instructions/PopInstructionPrototype.cs b/Source/Backlang.Driver/Core/Instructions/PopInstructionPrototype.cs
new file mode 100644
index 00000000..2a9371cf
--- /dev/null
+++ b/Source/Backlang.Driver/Core/Instructions/PopInstructionPrototype.cs
@@ -0,0 +1,18 @@
+namespace Backlang.Driver.Core.Instructions;
+
+internal class PopInstructionPrototype : InstructionPrototype
+{
+ public override IType ResultType => null;
+
+ public override int ParameterCount => 0;
+
+ public override IReadOnlyList CheckConformance(Instruction instance, MethodBody body)
+ {
+ return null;
+ }
+
+ public override InstructionPrototype Map(MemberMapping mapping)
+ {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Core/Instructions/TypeOfInstructionPrototype.cs b/Source/Backlang.Driver/Core/Instructions/TypeOfInstructionPrototype.cs
index 1ad8160e..8f18019e 100644
--- a/Source/Backlang.Driver/Core/Instructions/TypeOfInstructionPrototype.cs
+++ b/Source/Backlang.Driver/Core/Instructions/TypeOfInstructionPrototype.cs
@@ -21,4 +21,4 @@ public override InstructionPrototype Map(MemberMapping mapping)
{
return null;
}
-}
\ No newline at end of file
+}
diff --git a/Source/Backlang.Driver/Core/OperatorOverloadingHelpers.cs b/Source/Backlang.Driver/Core/OperatorOverloadingHelpers.cs
index afde8c54..182a864f 100644
--- a/Source/Backlang.Driver/Core/OperatorOverloadingHelpers.cs
+++ b/Source/Backlang.Driver/Core/OperatorOverloadingHelpers.cs
@@ -13,6 +13,8 @@ public static class OperatorOverloadingHelpers
["'&"] = "op_BitwiseAnd",
["'|"] = "op_BitwiseOr",
["'^"] = "op_ExclusiveOr",
+ ["'=="] = "op_Equality",
+ ["'!="] = "op_Inequality",
}.ToImmutableDictionary();
private static readonly ImmutableDictionary unMap = new Dictionary()
@@ -25,6 +27,10 @@ public static class OperatorOverloadingHelpers
["'&"] = "op_AddressOf",
["'%"] = "op_Percentage",
+ ["'suf?"] = "op_Unpacking",
+
+ ["implicit"] = "op_Implicit",
+ ["explicit"] = "op_Explicit",
}.ToImmutableDictionary();
public static bool TryGetOperator(this IType type, string op, out IMethod opMethod, params IType[] args)
diff --git a/Source/Backlang.Driver/InternalMacros/IntrinsicsMacros.cs b/Source/Backlang.Driver/InternalMacros/IntrinsicsMacros.cs
index 7710901b..299e8def 100644
--- a/Source/Backlang.Driver/InternalMacros/IntrinsicsMacros.cs
+++ b/Source/Backlang.Driver/InternalMacros/IntrinsicsMacros.cs
@@ -1,4 +1,5 @@
using LeMP;
+using Loyc.Syntax;
using System.Reflection;
namespace Backlang.Driver.InternalMacros;
@@ -37,10 +38,7 @@ public static LNode InlineBlock(LNode node, IMacroContext context)
return LNode.Call((Symbol)"'{}");
}
- if (intrinsicNames == null)
- {
- intrinsicNames = InitAvailableIntrinsicNames(compContext.CompilationTarget.IntrinsicType);
- }
+ intrinsicNames ??= InitAvailableIntrinsicNames(compContext.CompilationTarget.IntrinsicType);
var availableConstants =
GetAvailableConstants(compContext.CompilationTarget.IntrinsicType);
@@ -54,7 +52,7 @@ public static LNode InlineBlock(LNode node, IMacroContext context)
continue;
}
- calls = ConvertCall(calls, compContext, availableConstants, compContext.CompilationTarget.IntrinsicType);
+ calls = ConvertCall(calls, compContext, availableConstants);
var newCall = ConvertIntrinsic(calls, compContext.CompilationTarget.IntrinsicType);
newBodyArgs = newBodyArgs.Add(newCall);
@@ -63,7 +61,7 @@ public static LNode InlineBlock(LNode node, IMacroContext context)
return LNode.Call((Symbol)"'{}", newBodyArgs).WithStyle(NodeStyle.Operator);
}
- private static LNode ConvertCall(LNode calls, CompilerContext context, Dictionary availableConstants, Type intrinsicType)
+ private static LNode ConvertCall(LNode calls, CompilerContext context, Dictionary availableConstants)
{
var newArgs = new LNodeList();
diff --git a/Source/Backlang.Driver/InternalMacros/SyntacticMacros.cs b/Source/Backlang.Driver/InternalMacros/SyntacticMacros.cs
index f5e23337..88f95371 100644
--- a/Source/Backlang.Driver/InternalMacros/SyntacticMacros.cs
+++ b/Source/Backlang.Driver/InternalMacros/SyntacticMacros.cs
@@ -1,5 +1,4 @@
using LeMP;
-using Loyc.Collections;
using System.Text.RegularExpressions;
namespace Backlang.Driver.InternalMacros;
@@ -23,7 +22,11 @@ public static class SyntacticMacros
["bitwise_or"] = ("BitwiseOr", 2),
["exclusive_or"] = ("ExclusiveOr", 2),
+ ["equality"] = ("Equality", 2),
+ ["inequality"] = ("Inequality", 2),
+
["bitwise_not"] = ("OnesComplement", 1),
+ ["unpacking"] = ("Unpacking", 1),
["deref"] = ("Deref", 1),
["addrof"] = ("AddressOf", 2),
@@ -31,37 +34,28 @@ public static class SyntacticMacros
["percent"] = ("Percentage", 1),
};
- private static LNodeFactory F = new LNodeFactory(EmptySourceFile.Synthetic);
-
- [LexicalMacro("#autofree(hat) {}", "Frees the handles after using them in the body", "autofree")]
- public static LNode AutoFree(LNode @operator, IMacroContext context)
- {
- var body = @operator.Args.Last;
-
- var handles = @operator.Args.Take(@operator.Args.Count - 1);
-
- var freeCalls = LNode.List();
-
- foreach (var handle in handles)
- {
- freeCalls.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(handle, LNode.Id((Symbol)"Free"))).SetStyle(NodeStyle.Operator)));
- }
-
- return body.WithArgs(LNode.List().AddRange(body.Args).AddRange(freeCalls));
- }
+ private static readonly LNodeFactory F = new LNodeFactory(EmptySourceFile.Synthetic);
[LexicalMacro("constructor()", "Convert constructor() to .ctor() function", "#constructor", Mode = MacroMode.MatchIdentifierOrCall)]
- public static LNode Constructor(LNode @operator, IMacroContext context)
+ public static LNode Constructor(LNode node, IMacroContext context)
{
- return SyntaxTree.Signature(SyntaxTree.Type(".ctor", new()), SyntaxTree.Type("none", LNode.List()), @operator.Args[0].Args, new()).PlusArg(@operator.Args[1]).WithAttrs(@operator.Attrs);
+ var factory = new LNodeFactory(node.Source);
+ SyntaxTree.Factory = factory;
+
+ return SyntaxTree.Signature(SyntaxTree.Type(".ctor", new()),
+ SyntaxTree.Type("none", LNode.List()), node.Args[0].Args,
+ new()).PlusArg(node.Args[1]).WithAttrs(node.Attrs).WithRange(node.Range);
}
[LexicalMacro("destructor()", "Convert destructor() to .dtor() function", "#destructor", Mode = MacroMode.MatchIdentifierOrCall)]
- public static LNode Destructor(LNode @operator, IMacroContext context)
+ public static LNode Destructor(LNode node, IMacroContext context)
{
+ var factory = new LNodeFactory(node.Source);
+ SyntaxTree.Factory = factory;
+
return SyntaxTree.Signature(SyntaxTree.Type(".dtor", new()),
- SyntaxTree.Type("none", LNode.List()), @operator.Args[0].Args, new())
- .PlusArg(@operator.Args[1]).WithAttrs(@operator.Attrs);
+ SyntaxTree.Type("none", LNode.List()), node.Args[0].Args, new())
+ .PlusArg(node.Args[1]).WithAttrs(node.Attrs).WithRange(node.Range);
}
[LexicalMacro(".dtor()", "Convert destructor() or .dtor() to Finalize", ".dtor", Mode = MacroMode.MatchIdentifierOrCall)]
@@ -70,15 +64,56 @@ public static LNode DestructorNormalisation(LNode @operator, IMacroContext conte
return @operator.WithTarget(LNode.Id("Finalize"));
}
- [LexicalMacro("left /= right;", "Convert to left = left / something", "'/=", Mode = MacroMode.MatchIdentifierOrCall)]
+ [LexicalMacro("'/=", "Convert to left = left / something", "'/=", Mode = MacroMode.MatchIdentifierOrCall)]
public static LNode DivEquals(LNode @operator, IMacroContext context)
{
return ConvertToAssignment(@operator, CodeSymbols.Div);
}
- [LexicalMacro("operator", "Convert to public static op_", "#fn",
- Mode = MacroMode.MatchIdentifierOrCall | MacroMode.PriorityOverride)]
- public static LNode ExpandOperator(LNode @operator, IMacroContext context)
+ [LexicalMacro("#fn", "Transform function", "#fn",
+ Mode = MacroMode.MatchIdentifierOrCall | MacroMode.ProcessChildrenBefore)]
+ public static LNode TransformFunction(LNode node, IMacroContext context)
+ {
+ node = ExpandOperator(node, context);
+
+ node = ExpandNotnullAssertionPostfix(node, context);
+
+ return node;
+ }
+
+ private static LNode ExpandNotnullAssertionPostfix(LNode node, IMacroContext context)
+ {
+ var newBody = new LNodeList();
+ var newParameters = new LNodeList();
+
+ if(node.ArgCount == 0) return node;
+
+ foreach (var parameter in node[2].Args)
+ {
+ var nonNullAttribute = LNode.Id(Symbols.AssertNonNull);
+
+ if (parameter.Attrs.Contains(nonNullAttribute))
+ {
+ var name = parameter[1][0];
+
+ var throwNode = LNode.Call(CodeSymbols.Throw, LNode.List(LNode.Call(CodeSymbols.String, LNode.List(LNode.Literal($"Parameter '{name.Name}' is none")))));
+ var ifBody = LNode.Call(CodeSymbols.Braces, LNode.List(throwNode));
+
+ newBody = newBody.Add(SyntaxTree.If(LNode.Call(CodeSymbols.Eq, LNode.List(name, SyntaxTree.None())), ifBody, LNode.Missing));
+ }
+
+ newParameters.Add(parameter.WithoutAttrNamed(nonNullAttribute.Name));
+ }
+
+ newBody = newBody.AddRange(node[3].Args);
+
+ node = node.WithArgChanged(2, node[3].WithArgs(newParameters));
+ node = node.WithArgChanged(3, LNode.Call(CodeSymbols.Braces, newBody));
+
+ return node;
+ }
+
+ private static LNode ExpandOperator(LNode @operator, IMacroContext context)
{
var operatorAttribute = SyntaxTree.Factory.Id((Symbol)"#operator");
if (@operator.Attrs.Contains(operatorAttribute))
@@ -150,7 +185,7 @@ public static LNode HandleOperator(LNode @operator, IMacroContext context)
LNode.List(@operator.Args[0]));
}
- [LexicalMacro("Point::new()", "Convert ::New To CodeSymbols.New", "'::", Mode = MacroMode.MatchIdentifierOrCall)]
+ [LexicalMacro("'::'", "Convert ::New To CodeSymbols.New", "'::", Mode = MacroMode.MatchIdentifierOrCall)]
public static LNode Instantiation(LNode node, IMacroContext context)
{
if (node.Args.IsEmpty)
@@ -194,6 +229,17 @@ public static LNode MinusEquals(LNode @operator, IMacroContext context)
return ConvertToAssignment(@operator, CodeSymbols.Sub);
}
+
+ //ToDo: move to other stage to enable typecheck. only allowed if a type is nullable
+ [LexicalMacro("left !!= right;", "None check shotcut operator", "'!!=", Mode = MacroMode.MatchIdentifierOrCall)]
+ public static LNode NoneCheckShortcut(LNode node, IMacroContext context)
+ {
+ var condition = LNode.Call(CodeSymbols.NotEq, LNode.List(node[0], SyntaxTree.None()));
+ var body = LNode.List(LNode.Call(CodeSymbols.Assign, LNode.List(node[0], node[1])));
+
+ return SyntaxTree.If(condition, LNode.Call(CodeSymbols.Braces, body), LNode.Missing);
+ }
+
[LexicalMacro("left *= right;", "Convert to left = left * something", "'*=", Mode = MacroMode.MatchIdentifierOrCall)]
public static LNode MulEquals(LNode @operator, IMacroContext context)
{
@@ -239,24 +285,30 @@ public static LNode InterpolateString(LNode node, IMacroContext context)
string formatString = valueNode.Value.ToString();
if (formatString.Contains('$'))
{
- var interpolateOptions = GetInterpoltedStringOptions(formatString);
var formatArgs = new List();
int counter = 0;
- foreach (var item in interpolateOptions)
- {
- if (formatString[item.start - 1] == '\\')
+
+ formatString = Regex.Replace(formatString, "\\$(?\\w[0-9a-zA-Z_]*)(:(\\{(?[0-9a-zA-Z_]*)\\}))?", _ => {
+ var sb = new StringBuilder();
+ sb.Append('{').Append(counter++);
+
+ var options = _.Groups["options"].Value;
+
+ if (!string.IsNullOrEmpty(options))
{
- continue;
+ sb.Append(':').Append(options);
}
- formatString = formatString.Replace($"{item.name}", "{" + counter++ + "}");
+ sb.Append('}');
var varRange = new SourceRange(valueNode.Range.Source,
- item.start + node.Range.StartIndex + 1, item.length);
+ _.Index + node.Range.StartIndex + 1, _.Length);
- formatArgs.Add(SyntaxTree.Factory.Id(item.name[1..]).WithRange(varRange));
- }
+ formatArgs.Add(SyntaxTree.Factory.Id(_.Groups["name"].Value).WithRange(varRange));
+
+ return sb.ToString();
+ });
formatArgs.Insert(0, SyntaxTree.Factory.Call(CodeSymbols.String, LNode.List(SyntaxTree.Factory.Literal(formatString))));
@@ -267,25 +319,13 @@ public static LNode InterpolateString(LNode node, IMacroContext context)
return node;
}
- private static List<(string name, int start, int length)> GetInterpoltedStringOptions(string value)
+ private static LNode ConvertToAssignment(LNode node, Symbol symbol)
{
- var result = new List<(string name, int start, int length)>();
-
- var match = Regex.Matches(value, "\\$[a-zA-Z_][0-9a-zA-Z_]*");
+ var arg1 = node.Args[0];
+ var arg2 = node.Args[1];
- foreach (Match m in match)
- {
- result.Add((m.Value, m.Index, m.Length));
- }
-
- return result;
- }
-
- private static LNode ConvertToAssignment(LNode @operator, Symbol symbol)
- {
- var arg1 = @operator.Args[0];
- var arg2 = @operator.Args[1];
+ var factory = new LNodeFactory(node.Source);
- return F.Call(CodeSymbols.Assign, arg1, F.Call(symbol, arg1, arg2));
+ return factory.Call(CodeSymbols.Assign, arg1, factory.Call(symbol, arg1, arg2));
}
}
\ No newline at end of file
diff --git a/Source/Backlang.Driver/TypeDeducer.cs b/Source/Backlang.Driver/TypeDeducer.cs
index 6811f559..ca72c1e9 100644
--- a/Source/Backlang.Driver/TypeDeducer.cs
+++ b/Source/Backlang.Driver/TypeDeducer.cs
@@ -1,5 +1,6 @@
using Backlang.Codeanalysis.Core;
using Backlang.Contracts.TypeSystem;
+using System.Linq.Expressions;
namespace Backlang.Driver;
@@ -43,18 +44,15 @@ public static IType Deduce(LNode node, Scope scope, CompilerContext context, Qua
}
else if (node.Calls(CodeSymbols.Typeof))
{
- return context.Binder.ResolveTypes(new SimpleName("Type").Qualify("System")).First();
+ return Utils.ResolveType(context.Binder, typeof(Type));
}
else if (node.Calls(Symbols.Unit) && node is (_, var value, var unit))
{
- var resolvedUnit = TypeInheritanceStage.ResolveTypeWithModule(unit, context, modulename);
-
- if (!Utils.IsUnitType(context, resolvedUnit))
- {
- context.AddError(unit, $"{resolvedUnit} is not a unit type");
- }
-
- return new UnitType(Deduce(value, scope, context, modulename), resolvedUnit);
+ return DeduceUnitType(scope, context, modulename, value, unit);
+ }
+ else if (node.Calls(CodeSymbols.As) && node is (_, var expr, var castType))
+ {
+ return Deduce(castType, scope, context, modulename);
}
else if (node.ArgCount == 1 && node.Calls(CodeSymbols.Default))
{
@@ -94,6 +92,13 @@ public static IType Deduce(LNode node, Scope scope, CompilerContext context, Qua
}
else
{
+ var type = TypeInheritanceStage.ResolveTypeWithModule(node, context, modulename);
+
+ if (type != null)
+ {
+ return type;
+ }
+
var suggestion = LevensteinDistance.Suggest(node.Name.Name, scope.GetAllScopeNames());
context.AddError(node, $"{node.Name} cannot be resolved. Did you mean '{suggestion}'?");
@@ -103,6 +108,87 @@ public static IType Deduce(LNode node, Scope scope, CompilerContext context, Qua
return null;
}
+ public static IType DeduceFunctionReturnType(LNode funcDefinition, CompilerContext context, Scope scope, QualifiedName modulename)
+ {
+ var returnNodes = funcDefinition.Descendants().Where(_ => _.Calls(CodeSymbols.Return)).ToArray();
+
+ if (!returnNodes.Any())
+ {
+ return Utils.ResolveType(context.Binder, typeof(void));
+ }
+
+ if (returnNodes.Length == 1 && returnNodes[0].ArgCount == 1)
+ {
+ return Deduce(returnNodes[0][0], scope, context, modulename);
+ }
+
+ var types = returnNodes.Where(_ => _.ArgCount > 0).Select(_ => Deduce(_[0], scope, context, modulename));
+
+ if (!types.Any())
+ {
+ return null;
+ }
+
+ var aggregatedCommonType = types.Aggregate(FindCommonType);
+
+ if (aggregatedCommonType != null)
+ {
+ return aggregatedCommonType;
+ }
+
+ context.AddError(funcDefinition, ErrorID.DeducingTypeNotPossible);
+ return context.Environment.Void;
+ }
+
+ private static IType FindCommonType(IType first, IType second)
+ {
+ if (first == second)
+ {
+ return first;
+ }
+
+ if (ImplicitTypeCastTable.IsAssignableTo(first, second))
+ {
+ return first;
+ }
+ if (ImplicitTypeCastTable.IsAssignableTo(second, first))
+ {
+ return second;
+ }
+
+ if (second.BaseTypes.Count > 0 && second.BaseTypes[0] == first)
+ {
+ return first;
+ }
+
+ if (first.BaseTypes.Count > 0 && first.BaseTypes[0] == second)
+ {
+ return second;
+ }
+
+ if (first.BaseTypes.Count > 0 && second.BaseTypes.Count > 0)
+ {
+ if (first.BaseTypes[0].FullName.ToString() == "System.ValueType" || second.BaseTypes[0].FullName.ToString() == "System.ValueType")
+ {
+ return null;
+ }
+
+ if (first.BaseTypes[0].FullName.ToString() == "System.Object" || second.BaseTypes[0].FullName.ToString() == "System.Object")
+ {
+ return null;
+ }
+
+ if (first.BaseTypes[0] == second.BaseTypes[0])
+ {
+ return first.BaseTypes[0];
+ }
+
+ return FindCommonType(first.BaseTypes[0], second.BaseTypes[0]);
+ }
+
+ return null;
+ }
+
public static void ExpectType(LNode node, Scope scope, CompilerContext context, QualifiedName modulename, IType expectedType)
{
var deducedType = Deduce(node, scope, context, modulename);
@@ -125,6 +211,18 @@ public static IType NotExpectType(LNode node, Scope scope, CompilerContext conte
return deducedType;
}
+ private static IType DeduceUnitType(Scope scope, CompilerContext context, QualifiedName modulename, LNode value, LNode unit)
+ {
+ var resolvedUnit = TypeInheritanceStage.ResolveTypeWithModule(unit, context, modulename);
+
+ if (!Utils.IsUnitType(context, resolvedUnit))
+ {
+ context.AddError(unit, $"{resolvedUnit} is not a unit type");
+ }
+
+ return new UnitType(Deduce(value, scope, context, modulename), resolvedUnit);
+ }
+
private static IType DeduceArray(LNode node, Scope scope, CompilerContext context, QualifiedName modulename)
{
//ToDo: Make deducing array type better
@@ -172,20 +270,20 @@ private static IType DeduceTuple(LNode node, Scope scope, CompilerContext contex
return tupleType.MakeGenericType(generics);
}
- private static IType DeduceBinary(LNode node, Scope scope, CompilerContext context, QualifiedName modulename)
+ private static IType DeduceBinary(LNode node, Scope scope, CompilerContext context, QualifiedName moduleName)
{
if (node.Calls(CodeSymbols.Add) || node.Calls(CodeSymbols.Mul)
|| node.Calls(CodeSymbols.Div) || node.Calls(CodeSymbols.Sub) || node.Calls(CodeSymbols.AndBits)
- || node.Calls(CodeSymbols.OrBits) || node.Calls(CodeSymbols.Xor) || node.Calls(CodeSymbols.Mod))
+ || node.Calls(CodeSymbols.OrBits) || node.Calls((Symbol)"'^") || node.Calls(CodeSymbols.Mod))
{
- return DeduceBinaryHelper(node, scope, context, modulename);
+ return DeduceBinaryHelper(node, scope, context, moduleName);
}
else if (node.Calls(CodeSymbols.LT)
|| node.Calls(CodeSymbols.GT) || node.Calls(CodeSymbols.LE)
|| node.Calls(CodeSymbols.GE))
{
- NotExpectType(node[0], scope, context, modulename, context.Environment.Boolean);
- NotExpectType(node[1], scope, context, modulename, context.Environment.Boolean);
+ NotExpectType(node[0], scope, context, moduleName, context.Environment.Boolean);
+ NotExpectType(node[1], scope, context, moduleName, context.Environment.Boolean);
return context.Environment.Boolean;
}
@@ -195,58 +293,88 @@ private static IType DeduceBinary(LNode node, Scope scope, CompilerContext conte
}
else if (node.Calls(CodeSymbols.As))
{
- if (TypenameTable.ContainsKey(node.Args[1].Name.Name))
- {
- var typName = LNode.Id(TypenameTable[node.Args[1].Name.Name]);
- return Deduce(typName, scope, context, modulename);
- }
-
- return Deduce(node.Args[1], scope, context, modulename);
+ return DeduceExplicitCast(node, scope, context, moduleName);
}
else if (node.Calls(CodeSymbols.Dot))
{
- var qualified = ConversionUtils.GetQualifiedName(node);
- var resolved = context.Binder.ResolveTypes(qualified).FirstOrDefault();
-
- if (resolved == null)
- {
- var left = Deduce(node.Args[0], scope, context, modulename); //Todo: implement deducing for members
- }
-
- return resolved;
+ return DeduceMember(node, scope, context, moduleName);
}
else if (node.Calls(CodeSymbols.ColonColon))
{
- var type = Deduce(node.Args[0], scope, context, modulename);
- var fnName = node.Args[1].Name;
+ return DeduceStaticMethod(node, scope, context, moduleName);
+ }
- var methods = type.Methods.Where(_ => _.Name.ToString() == fnName.ToString());
- var deducedArgs = new List();
+ return null;
+ }
- foreach (var arg in node.Args[1].Args)
- {
- deducedArgs.Add(Deduce(arg, scope, context, modulename));
- }
+ private static IType DeduceStaticMethod(LNode node, Scope scope, CompilerContext context, QualifiedName moduleName)
+ {
+ var type = Deduce(node.Args[0], scope, context, moduleName);
+ var fnName = node.Args[1].Name;
+
+ var methods = type.Methods.Where(_ => _.Name.ToString() == fnName.ToString());
+ var deducedArgs = new List();
- methods = methods.Where(_ => _.Parameters.Count == deducedArgs.Count);
+ foreach (var arg in node.Args[1].Args)
+ {
+ deducedArgs.Add(Deduce(arg, scope, context, moduleName));
+ }
- if (methods.Any())
+ methods = methods.Where(_ => _.Parameters.Count == deducedArgs.Count);
+
+ if (methods.Any())
+ {
+ foreach (var method in methods)
{
- foreach (var method in methods)
+ if (!ImplementationStage.MatchesParameters(method, deducedArgs))
{
- if (ImplementationStage.MatchesParameters(method, deducedArgs))
- {
- return method.ReturnParameter.Type;
- }
+ continue;
}
+
+ return method.ReturnParameter.Type;
}
- else
+ }
+ else
+ {
+ context.AddError(node, $"Mismatching Parameter count: {type.FullName.ToString() + "::" + fnName}()");
+ }
+
+ return null;
+ }
+
+ private static IType DeduceMember(LNode node, Scope scope, CompilerContext context, QualifiedName modulename)
+ {
+ var qualified = ConversionUtils.GetQualifiedName(node);
+ var resolved = context.Binder.ResolveTypes(qualified).FirstOrDefault();
+
+ if (resolved == null)
+ {
+ var left = Deduce(node.Args[0], scope, context, modulename);
+ var field = left.Fields.FirstOrDefault(_ => _.Name.ToString() == qualified.Name.ToString());
+
+ if (field != null)
{
- context.AddError(node, $"Mismatching Parameter count: {type.FullName.ToString() + "::" + fnName}()");
+ return field.FieldType;
}
+
+ var funcArgs = node[1].Args.Select(_ => Deduce(_, scope, context, modulename));
+ var func = context.Binder.FindFunction(left.ToString() + "::" + qualified.Name + "(" + string.Join(',', funcArgs) + ")");
+
+ return func.ReturnParameter.Type;
}
- return null;
+ return resolved;
+ }
+
+ private static IType DeduceExplicitCast(LNode node, Scope scope, CompilerContext context, QualifiedName modulename)
+ {
+ if (TypenameTable.ContainsKey(node.Args[1].Name.Name))
+ {
+ var typName = LNode.Id(TypenameTable[node.Args[1].Name.Name]);
+ return Deduce(typName, scope, context, modulename);
+ }
+
+ return Deduce(node.Args[1], scope, context, modulename);
}
private static IType DeduceUnary(LNode node, Scope scope, CompilerContext context, QualifiedName modulename)
@@ -301,6 +429,15 @@ private static IType DeduceBinaryHelper(LNode node, Scope scope, CompilerContext
if (left != right) //ToDo: Add implicit casting check
{
+ if (left is UnitType && right is not UnitType)
+ {
+ return left;
+ }
+ else if (right is UnitType && left is not UnitType)
+ {
+ return right;
+ }
+
if (left.IsPointerType())
{
ExpectType(node.Args[1], scope, context, modulename, context.Environment.Int32);
diff --git a/Source/Backlang.Driver/Utils.cs b/Source/Backlang.Driver/Utils.cs
index db1aca04..7731185e 100644
--- a/Source/Backlang.Driver/Utils.cs
+++ b/Source/Backlang.Driver/Utils.cs
@@ -1,4 +1,6 @@
using Backlang.Core.CompilerService;
+using Furesoft.Core.CodeDom.Compiler.TypeSystem;
+using System.Runtime.CompilerServices;
namespace Backlang.Driver;
@@ -12,29 +14,9 @@ public static FlowGraphBuilder CreateGraphBuilder()
return graph;
}
- public static QualifiedName QualifyNamespace(string @namespace)
- {
- var spl = @namespace.Split('.');
-
- QualifiedName? name = null;
-
- foreach (var path in spl)
- {
- if (name == null)
- {
- name = new SimpleName(path).Qualify();
- continue;
- }
-
- name = new SimpleName(path).Qualify(name.Value);
- }
-
- return name.Value;
- }
-
public static DescribedType ResolveType(TypeResolver resolver, Type type)
{
- var ns = QualifyNamespace(type.Namespace);
+ var ns = ConversionUtils.QualifyNamespace(type.Namespace);
return (DescribedType)resolver.ResolveTypes(new SimpleName(type.Name).Qualify(ns))?.FirstOrDefault();
}
@@ -65,4 +47,10 @@ public static bool IsUnitType(CompilerContext context, IType resolvedUnit)
return attr.Select(_ => _.AttributeType).Contains(attrType);
}
+
+ public static void AddCompilerGeneratedAttribute(TypeResolver binder, DescribedType type) {
+ var attributeType = ResolveType(binder, typeof(CompilerGeneratedAttribute));
+
+ type.AddAttribute(new DescribedAttribute(attributeType));
+ }
}
\ No newline at end of file
diff --git a/Source/Backlang.NET.Sdk/Backlang.NET.Sdk.csproj b/Source/Backlang.NET.Sdk/Backlang.NET.Sdk.csproj
index 250177a1..a978dbe2 100644
--- a/Source/Backlang.NET.Sdk/Backlang.NET.Sdk.csproj
+++ b/Source/Backlang.NET.Sdk/Backlang.NET.Sdk.csproj
@@ -51,8 +51,8 @@
-
-
+
+
diff --git a/Source/Backlang.NET.Sdk/BuildTask.cs b/Source/Backlang.NET.Sdk/BuildTask.cs
index dd15754a..7d3c36b6 100644
--- a/Source/Backlang.NET.Sdk/BuildTask.cs
+++ b/Source/Backlang.NET.Sdk/BuildTask.cs
@@ -81,21 +81,23 @@ public override bool Execute()
}
var context = new CompilerContext();
- context.InputFiles = Compile;
- context.OutputFilename = OutputName;
- context.OutputType = OutputType;
+ context.Options.InputFiles = Compile;
+ context.Options.OutputFilename = OutputName;
+ context.Options.OutputType = OutputType;
+ context.Options.Version = Version;
+ context.Options.EmbeddedResource = Resources;
+ context.Options.TargetFramework = TargetFramework;
+
context.TempOutputPath = TempOutputPath;
context.OutputPath = OutputPath;
context.MacroReferences = MacroReferences;
context.ResultingOutputPath = ResultingOutputPath;
context.ProjectFile = ProjectFile;
- context.EmbeddedResource = Resources;
context.CorLib = CorLib;
- context.Version = Version;
if (!string.IsNullOrEmpty(OutputTree))
{
- context.OutputTree = bool.Parse(OutputTree);
+ context.Options.OutputTree = bool.Parse(OutputTree);
}
CompilerDriver.Compile(context);
diff --git a/Source/Backlang.NET.Sdk/build/Backlang.Version.props b/Source/Backlang.NET.Sdk/build/Backlang.Version.props
index 595c7f6f..224618b2 100644
--- a/Source/Backlang.NET.Sdk/build/Backlang.Version.props
+++ b/Source/Backlang.NET.Sdk/build/Backlang.Version.props
@@ -1,5 +1,5 @@
-1.0.80
+1.0.83
diff --git a/Source/Backlang.WasmBridge/Backlang.WasmBridge.csproj b/Source/Backlang.WasmBridge/Backlang.WasmBridge.csproj
new file mode 100644
index 00000000..c3559195
--- /dev/null
+++ b/Source/Backlang.WasmBridge/Backlang.WasmBridge.csproj
@@ -0,0 +1,16 @@
+
+
+ net7.0
+ browser-wasm
+ main.mjs
+ Exe
+ true
+ true
+ preview
+ True
+
+
+
+
+
+
diff --git a/Source/Backlang.WasmBridge/Bridge.cs b/Source/Backlang.WasmBridge/Bridge.cs
new file mode 100644
index 00000000..d04f0f46
--- /dev/null
+++ b/Source/Backlang.WasmBridge/Bridge.cs
@@ -0,0 +1,34 @@
+using Backlang.Contracts;
+using Backlang.Driver;
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices.JavaScript;
+using System.Text;
+
+public partial class Bridge
+{
+ [JSExport]
+ public static string CompileAndRun(string src)
+ {
+ var context = new CompilerContext();
+ context.Playground = new() { IsPlayground = true, Source = src };
+
+ var assemblyStream = new MemoryStream();
+
+ context.OutputStream = assemblyStream;
+
+ var output = new MemoryStream();
+ var sw = new StreamWriter(output);
+ Console.SetOut(sw);
+
+ CompilerDriver.Compile(context);
+
+ assemblyStream.Seek(0, SeekOrigin.Begin);
+
+ //var assembly = Assembly.Load(assemblyStream.ToArray());
+ //assembly.EntryPoint.Invoke(null, Array.Empty
-
+
diff --git a/Source/Version.props b/Source/Version.props
index 1f763704..ef52452b 100644
--- a/Source/Version.props
+++ b/Source/Version.props
@@ -1,5 +1,5 @@
- 1.0.80
+ 1.0.83
\ No newline at end of file
diff --git a/Source/Backlang.Driver/Resources/compilation.runtimeconfig.json b/compilation.runtimeconfig.json
similarity index 59%
rename from Source/Backlang.Driver/Resources/compilation.runtimeconfig.json
rename to compilation.runtimeconfig.json
index 46de2091..a01ee703 100644
--- a/Source/Backlang.Driver/Resources/compilation.runtimeconfig.json
+++ b/compilation.runtimeconfig.json
@@ -1,9 +1,9 @@
{
"runtimeOptions": {
- "tfm": "net7.0",
+ "tfm": null,
"framework": {
"name": "Microsoft.NETCore.App",
- "version": "7.0.0-preview.2.22152.2"
+ "version": "7.0.0"
}
}
}
\ No newline at end of file