commit
e11476f614
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
|
using FluentAssertions;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Parser.Tests
|
namespace Parser.Tests
|
||||||
{
|
{
|
||||||
@ -37,12 +39,33 @@ namespace Parser.Tests
|
|||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var statement = actual.Root.Body.Statements[0].AsNode();
|
var statement = actual.Root.Body.Statements[0].AsNode();
|
||||||
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
||||||
if (statement is null)
|
Assert.IsType<BinaryOperationExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)statement!).Expression);
|
||||||
{
|
}
|
||||||
throw new System.Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.IsType<BinaryOperationExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)statement).Expression);
|
[Fact]
|
||||||
|
public void ParseExpressionStatementWithSemicolon()
|
||||||
|
{
|
||||||
|
var text = "2 + 3;";
|
||||||
|
var sut = GetSut(text);
|
||||||
|
var actual = sut.Parse();
|
||||||
|
Assert.Single(actual.Root.Body.Statements);
|
||||||
|
var statement = actual.Root.Body.Statements[0].AsNode();
|
||||||
|
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
||||||
|
Assert.IsType<BinaryOperationExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)statement!).Expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseExpressionStatementWithSemicolonAfterNewLine()
|
||||||
|
{
|
||||||
|
var text = "2 + 3\n;";
|
||||||
|
var sut = GetSut(text);
|
||||||
|
var actual = sut.Parse();
|
||||||
|
Assert.Equal(2, actual.Root.Body.Statements.Count);
|
||||||
|
var statement1 = actual.Root.Body.Statements[0].AsNode();
|
||||||
|
Assert.IsType<ExpressionStatementSyntaxNode>(statement1);
|
||||||
|
Assert.IsType<BinaryOperationExpressionSyntaxNode>(((ExpressionStatementSyntaxNode)statement1!).Expression);
|
||||||
|
var statement2 = actual.Root.Body.Statements[1].AsToken();
|
||||||
|
Assert.Equal(TokenKind.SemicolonToken, statement2.Kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -74,7 +97,7 @@ namespace Parser.Tests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void ProvidePosition()
|
public void ProvidePosition()
|
||||||
{
|
{
|
||||||
var text = "2 + 3";
|
var text = "% Comment\n 2 + 3";
|
||||||
var sut = GetSut(text);
|
var sut = GetSut(text);
|
||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var statement = actual.Root.Body.Statements[0].AsNode() as ExpressionStatementSyntaxNode;
|
var statement = actual.Root.Body.Statements[0].AsNode() as ExpressionStatementSyntaxNode;
|
||||||
@ -83,8 +106,79 @@ namespace Parser.Tests
|
|||||||
var operation = expression.Operation;
|
var operation = expression.Operation;
|
||||||
var rhs = expression.Rhs;
|
var rhs = expression.Rhs;
|
||||||
Assert.Equal(0, lhs.Position);
|
Assert.Equal(0, lhs.Position);
|
||||||
Assert.Equal(2, operation.Position);
|
Assert.Equal(14, operation.Position);
|
||||||
Assert.Equal(4, rhs.Position);
|
Assert.Equal(16, rhs.Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ProvideFullSpan()
|
||||||
|
{
|
||||||
|
var text = "% Comment\n 2 + 3";
|
||||||
|
var sut = GetSut(text);
|
||||||
|
var actual = sut.Parse();
|
||||||
|
var statement = actual.Root.Body.Statements[0].AsNode() as ExpressionStatementSyntaxNode;
|
||||||
|
var expression = statement!.Expression as BinaryOperationExpressionSyntaxNode;
|
||||||
|
var lhs = expression!.Lhs;
|
||||||
|
var operation = expression.Operation;
|
||||||
|
var rhs = expression.Rhs;
|
||||||
|
expression.FullSpan.Start.Should().Be(0);
|
||||||
|
expression.FullSpan.End.Should().Be(17);
|
||||||
|
lhs.FullSpan.Start.Should().Be(0);
|
||||||
|
lhs.FullSpan.End.Should().Be(14);
|
||||||
|
operation.FullSpan.Start.Should().Be(14);
|
||||||
|
operation.FullSpan.End.Should().Be(16);
|
||||||
|
rhs.FullSpan.Start.Should().Be(16);
|
||||||
|
rhs.FullSpan.End.Should().Be(17);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ProvideSpan()
|
||||||
|
{
|
||||||
|
var text = "% Comment\n 2 + 3";
|
||||||
|
var sut = GetSut(text);
|
||||||
|
var actual = sut.Parse();
|
||||||
|
var statement = actual.Root.Body.Statements[0].AsNode() as ExpressionStatementSyntaxNode;
|
||||||
|
var expression = statement!.Expression as BinaryOperationExpressionSyntaxNode;
|
||||||
|
var lhs = expression!.Lhs;
|
||||||
|
var operation = expression.Operation;
|
||||||
|
var rhs = expression.Rhs;
|
||||||
|
expression.Span.Start.Should().Be(12);
|
||||||
|
expression.Span.End.Should().Be(17);
|
||||||
|
lhs.Span.Start.Should().Be(12);
|
||||||
|
lhs.Span.End.Should().Be(13);
|
||||||
|
operation.Span.Start.Should().Be(14);
|
||||||
|
operation.Span.End.Should().Be(15);
|
||||||
|
rhs.Span.Start.Should().Be(16);
|
||||||
|
rhs.Span.End.Should().Be(17);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NotHangOnUnknownSyntax()
|
||||||
|
{
|
||||||
|
var text = @"
|
||||||
|
classdef myClass
|
||||||
|
properties
|
||||||
|
Channel;
|
||||||
|
NodeID;
|
||||||
|
Node;
|
||||||
|
end
|
||||||
|
methods
|
||||||
|
function this = sendData(this, arg1, arg2)
|
||||||
|
arguments
|
||||||
|
this (1,1) myClass
|
||||||
|
arg1 (1,1) double {mustBeNonnegative}
|
||||||
|
arg2 (1,1) double {mustBeNonnegative}
|
||||||
|
end
|
||||||
|
If (arg1 = 0)
|
||||||
|
this.NodeID = 3;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function this = getData(this, arg1, arg2)
|
||||||
|
end
|
||||||
|
end";
|
||||||
|
var sut = GetSut(text);
|
||||||
|
Func<SyntaxTree> action = sut.Parse;
|
||||||
|
action.Should().Throw<ParsingException>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Parser.Tests
|
namespace Parser.Tests
|
||||||
@ -56,7 +57,35 @@ namespace Parser.Tests
|
|||||||
Assert.Equal(text, actualText);
|
Assert.Equal(text, actualText);
|
||||||
Assert.Equal(text.Length, actualWidth);
|
Assert.Equal(text.Length, actualWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(FilesData))]
|
||||||
|
public void TestLeadingAndTrailingTrivia(string fileName)
|
||||||
|
{
|
||||||
|
var text = File.ReadAllText(fileName);
|
||||||
|
var window = new TextWindowWithNull(text, fileName);
|
||||||
|
var parser = CreateParser(window);
|
||||||
|
var tree = parser.Parse();
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var maybeLeadingTrivia = tree.Root.LeadingTrivia;
|
||||||
|
var maybeTrailingTrivia = tree.Root.TrailingTrivia;
|
||||||
|
if (maybeLeadingTrivia is SyntaxTriviaList leadingTrivia)
|
||||||
|
{
|
||||||
|
sb.Append(leadingTrivia.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(tree.Root.Text);
|
||||||
|
|
||||||
|
if (maybeTrailingTrivia is SyntaxTriviaList trailingTrivia)
|
||||||
|
{
|
||||||
|
sb.Append(trailingTrivia.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
|
var actualText = sb.ToString();
|
||||||
|
Assert.Equal(text, actualText);
|
||||||
|
}
|
||||||
|
|
||||||
public static IEnumerable<object[]> FilesData()
|
public static IEnumerable<object[]> FilesData()
|
||||||
{
|
{
|
||||||
return Files().Select(fileName => new object[] { fileName });
|
return Files().Select(fileName => new object[] { fileName });
|
||||||
|
@ -13,24 +13,37 @@ namespace Parser.Binding
|
|||||||
{
|
{
|
||||||
private readonly DiagnosticsBag _diagnostics = new DiagnosticsBag();
|
private readonly DiagnosticsBag _diagnostics = new DiagnosticsBag();
|
||||||
|
|
||||||
public static BoundProgram BindProgram(SyntaxTree syntaxTree)
|
private BoundProgram BindProgramInternal(SyntaxTree syntaxTree)
|
||||||
{
|
{
|
||||||
var binder = new Binder();
|
var boundRoot = BindRoot(syntaxTree.NullRoot);
|
||||||
var boundRoot = binder.BindRoot(syntaxTree.NullRoot);
|
|
||||||
var statements = ((BoundBlockStatement)boundRoot.File.Body).Statements;
|
var statements = ((BoundBlockStatement)boundRoot.File.Body).Statements;
|
||||||
var functionsBuilder = ImmutableDictionary.CreateBuilder<FunctionSymbol, LoweredFunction>();
|
var functionsBuilder = ImmutableDictionary.CreateBuilder<FunctionSymbol, LoweredFunction>();
|
||||||
var globalStatements = statements.Where(s => s.Kind != BoundNodeKind.FunctionDeclaration).ToArray();
|
var globalStatements = statements.Where(s => s.Kind != BoundNodeKind.FunctionDeclaration).ToArray();
|
||||||
var mainFunction = (FunctionSymbol?)null;
|
var mainFunction = (FunctionSymbol?)null;
|
||||||
var scriptFunction = (FunctionSymbol?)null;
|
var scriptFunction = (FunctionSymbol?)null;
|
||||||
|
var functions = statements.OfType<BoundFunctionDeclaration>().ToArray();
|
||||||
if (globalStatements.Length > 0)
|
if (globalStatements.Length > 0)
|
||||||
{
|
{
|
||||||
// we have to gather all bound expression statements into a "script" function.
|
// we have to gather all bound expression statements into a "Main" function.
|
||||||
scriptFunction = new FunctionSymbol("%script");
|
scriptFunction = new FunctionSymbol("Main");
|
||||||
|
foreach (var f in functions) {
|
||||||
|
if (f.Name == "Main")
|
||||||
|
{
|
||||||
|
_diagnostics.ReportMainIsNotAllowed(
|
||||||
|
f.Syntax.Span);
|
||||||
|
return new BoundProgram(
|
||||||
|
_diagnostics.ToImmutableArray(),
|
||||||
|
mainFunction: null,
|
||||||
|
scriptFunction: null,
|
||||||
|
functions: functionsBuilder.ToImmutable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body = Block(globalStatements[0].Syntax, globalStatements);
|
var body = Block(globalStatements[0].Syntax, globalStatements);
|
||||||
var loweredBody = Lowerer.Lower(body);
|
var loweredBody = Lowerer.Lower(body);
|
||||||
var declaration = new BoundFunctionDeclaration(
|
var declaration = new BoundFunctionDeclaration(
|
||||||
syntax: globalStatements[0].Syntax,
|
syntax: globalStatements[0].Syntax,
|
||||||
name: "%script",
|
name: "Main",
|
||||||
inputDescription: ImmutableArray<ParameterSymbol>.Empty,
|
inputDescription: ImmutableArray<ParameterSymbol>.Empty,
|
||||||
outputDescription: ImmutableArray<ParameterSymbol>.Empty,
|
outputDescription: ImmutableArray<ParameterSymbol>.Empty,
|
||||||
body: body);
|
body: body);
|
||||||
@ -38,7 +51,7 @@ namespace Parser.Binding
|
|||||||
functionsBuilder.Add(scriptFunction, loweredFunction);
|
functionsBuilder.Add(scriptFunction, loweredFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
var functions = statements.OfType<BoundFunctionDeclaration>().ToArray();
|
|
||||||
var first = true;
|
var first = true;
|
||||||
foreach (var function in functions)
|
foreach (var function in functions)
|
||||||
{
|
{
|
||||||
@ -55,12 +68,18 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new BoundProgram(
|
return new BoundProgram(
|
||||||
binder._diagnostics.ToImmutableArray(),
|
_diagnostics.ToImmutableArray(),
|
||||||
mainFunction,
|
mainFunction,
|
||||||
scriptFunction,
|
scriptFunction,
|
||||||
functionsBuilder.ToImmutable());
|
functionsBuilder.ToImmutable());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BoundProgram BindProgram(SyntaxTree syntaxTree)
|
||||||
|
{
|
||||||
|
var binder = new Binder();
|
||||||
|
return binder.BindProgramInternal(syntaxTree);
|
||||||
|
}
|
||||||
|
|
||||||
private static LoweredFunction LowerFunction(BoundFunctionDeclaration declaration)
|
private static LoweredFunction LowerFunction(BoundFunctionDeclaration declaration)
|
||||||
{
|
{
|
||||||
var loweredBody = Lowerer.Lower(declaration.Body);
|
var loweredBody = Lowerer.Lower(declaration.Body);
|
||||||
@ -101,7 +120,7 @@ namespace Parser.Binding
|
|||||||
TokenKind.ExpressionStatement =>
|
TokenKind.ExpressionStatement =>
|
||||||
BindExpressionStatement((ExpressionStatementSyntaxNode)node),
|
BindExpressionStatement((ExpressionStatementSyntaxNode)node),
|
||||||
TokenKind.ForStatement =>
|
TokenKind.ForStatement =>
|
||||||
BindForStatement((ForStatementSyntaxNode)node),
|
BindForStatement((ForStatementSyntaxNode)node)!,
|
||||||
TokenKind.FunctionDeclaration =>
|
TokenKind.FunctionDeclaration =>
|
||||||
BindFunctionDeclaration((FunctionDeclarationSyntaxNode)node),
|
BindFunctionDeclaration((FunctionDeclarationSyntaxNode)node),
|
||||||
TokenKind.IfStatement =>
|
TokenKind.IfStatement =>
|
||||||
@ -117,11 +136,6 @@ namespace Parser.Binding
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundWhileStatement BindWhileStatement(WhileStatementSyntaxNode node)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private BoundTryCatchStatement BindTryCatchStatement(TryCatchStatementSyntaxNode node)
|
private BoundTryCatchStatement BindTryCatchStatement(TryCatchStatementSyntaxNode node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@ -250,15 +264,42 @@ namespace Parser.Binding
|
|||||||
return new ParameterSymbol(parameter.Text);
|
return new ParameterSymbol(parameter.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundForStatement BindForStatement(ForStatementSyntaxNode node)
|
private BoundForStatement? BindForStatement(ForStatementSyntaxNode node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var loopVariable = BindLoopVariable(node.Assignment.Lhs);
|
||||||
|
if (loopVariable is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var loopedExpression = BindExpression(node.Assignment.Rhs);
|
||||||
|
var body = BindStatement(node.Body);
|
||||||
|
return ForStatement(node, loopVariable, loopedExpression, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoundIdentifierNameExpression? BindLoopVariable(ExpressionSyntaxNode node)
|
||||||
|
{
|
||||||
|
if (node.Kind != TokenKind.IdentifierNameExpression)
|
||||||
|
{
|
||||||
|
_diagnostics.ReportForLoopWithoutVariable(node.Span);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Identifier(node, ((IdentifierNameExpressionSyntaxNode)node).Name.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoundWhileStatement BindWhileStatement(WhileStatementSyntaxNode node)
|
||||||
|
{
|
||||||
|
var condition = BindConversion(BindExpression(node.Condition), TypeSymbol.Boolean);
|
||||||
|
var body = BindStatement(node.Body);
|
||||||
|
return WhileStatement(node, condition, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundExpressionStatement BindExpressionStatement(ExpressionStatementSyntaxNode node)
|
private BoundExpressionStatement BindExpressionStatement(ExpressionStatementSyntaxNode node)
|
||||||
{
|
{
|
||||||
var expression = BindExpression(node.Expression);
|
var expression = BindExpression(node.Expression);
|
||||||
return ExpressionStatement(node, expression);
|
var discardResult = node.Semicolon is not null;
|
||||||
|
return ExpressionStatement(node, expression, discardResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundExpression BindExpression(ExpressionSyntaxNode node)
|
private BoundExpression BindExpression(ExpressionSyntaxNode node)
|
||||||
@ -326,11 +367,37 @@ namespace Parser.Binding
|
|||||||
return Assignment(node, left, right);
|
return Assignment(node, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BoundExpression BindConversion(BoundExpression expression, TypeSymbol targetType)
|
||||||
|
{
|
||||||
|
var conversion = Conversion.Classify(expression.Type, targetType);
|
||||||
|
if (!conversion.Exists)
|
||||||
|
{
|
||||||
|
return new BoundErrorExpression(expression.Syntax);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conversion.IsIdentity)
|
||||||
|
{
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Conversion(expression.Syntax, targetType, expression);
|
||||||
|
}
|
||||||
|
|
||||||
private BoundBinaryOperationExpression BindBinaryOperationExpression(BinaryOperationExpressionSyntaxNode node)
|
private BoundBinaryOperationExpression BindBinaryOperationExpression(BinaryOperationExpressionSyntaxNode node)
|
||||||
{
|
{
|
||||||
var left = BindExpression(node.Lhs);
|
var left = BindExpression(node.Lhs);
|
||||||
var right = BindExpression(node.Rhs);
|
var right = BindExpression(node.Rhs);
|
||||||
return BinaryOperation(node, left, node.Operation.Kind, right);
|
var op = BoundBinaryOperator.GetOperator(node.Operation.Kind, left.Type, right.Type);
|
||||||
|
if (op is null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Unknown binary operator '{node.Operation.Kind}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return BinaryOperation(
|
||||||
|
node,
|
||||||
|
BindConversion(left, op.Left),
|
||||||
|
op,
|
||||||
|
BindConversion(right, op.Right));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundCellArrayElementAccessExpression BindCellArrayElementAccessExpression(CellArrayElementAccessExpressionSyntaxNode node)
|
private BoundCellArrayElementAccessExpression BindCellArrayElementAccessExpression(CellArrayElementAccessExpressionSyntaxNode node)
|
||||||
@ -403,7 +470,15 @@ namespace Parser.Binding
|
|||||||
private BoundNumberLiteralExpression BindNumberLiteralExpression(NumberLiteralExpressionSyntaxNode node)
|
private BoundNumberLiteralExpression BindNumberLiteralExpression(NumberLiteralExpressionSyntaxNode node)
|
||||||
{
|
{
|
||||||
var value = (double)node.Number.Value!;
|
var value = (double)node.Number.Value!;
|
||||||
return NumberLiteral(node, value);
|
var intValue = (int)Math.Round(value);
|
||||||
|
if (intValue == value)
|
||||||
|
{
|
||||||
|
return NumberIntLiteral(node, intValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NumberDoubleLiteral(node, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundExpression BindParenthesizedExpression(ParenthesizedExpressionSyntaxNode node)
|
private BoundExpression BindParenthesizedExpression(ParenthesizedExpressionSyntaxNode node)
|
||||||
@ -420,7 +495,16 @@ namespace Parser.Binding
|
|||||||
private BoundUnaryOperationExpression BindUnaryPrefixOperationExpression(UnaryPrefixOperationExpressionSyntaxNode node)
|
private BoundUnaryOperationExpression BindUnaryPrefixOperationExpression(UnaryPrefixOperationExpressionSyntaxNode node)
|
||||||
{
|
{
|
||||||
var operand = BindExpression(node.Operand);
|
var operand = BindExpression(node.Operand);
|
||||||
return UnaryOperation(node, node.Operation.Kind, operand);
|
var op = BoundUnaryOperator.GetOperator(node.Operation.Kind, operand.Type);
|
||||||
|
if (op is null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Unknown binary operator '{node.Operation.Kind}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnaryOperation(
|
||||||
|
node,
|
||||||
|
op,
|
||||||
|
BindConversion(operand, op.Result));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundUnaryOperationExpression BindUnaryPostfixOperationExpression(UnaryPostfixOperationExpressionSyntaxNode node)
|
private BoundUnaryOperationExpression BindUnaryPostfixOperationExpression(UnaryPostfixOperationExpressionSyntaxNode node)
|
||||||
|
@ -4,45 +4,164 @@ namespace Parser.Binding
|
|||||||
{
|
{
|
||||||
public class BoundBinaryOperator
|
public class BoundBinaryOperator
|
||||||
{
|
{
|
||||||
private static BoundBinaryOperator[] _operators =
|
private static BoundBinaryOperator[] _specificOperators =
|
||||||
{
|
{
|
||||||
new BoundBinaryOperator(TokenKind.EqualsToken, BoundBinaryOperatorKind.Equals),
|
new BoundBinaryOperator(
|
||||||
new BoundBinaryOperator(TokenKind.PipePipeToken, BoundBinaryOperatorKind.PipePipe),
|
TokenKind.LessToken,
|
||||||
new BoundBinaryOperator(TokenKind.AmpersandAmpersandToken, BoundBinaryOperatorKind.AmpersandAmpersand),
|
BoundBinaryOperatorKind.LessInt,
|
||||||
new BoundBinaryOperator(TokenKind.PipeToken, BoundBinaryOperatorKind.Pipe),
|
TypeSymbol.Int,
|
||||||
new BoundBinaryOperator(TokenKind.AmpersandToken, BoundBinaryOperatorKind.Ampersand),
|
TypeSymbol.Boolean),
|
||||||
new BoundBinaryOperator(TokenKind.LessToken, BoundBinaryOperatorKind.Less),
|
new BoundBinaryOperator(
|
||||||
new BoundBinaryOperator(TokenKind.LessOrEqualsToken, BoundBinaryOperatorKind.LessOrEquals),
|
TokenKind.PlusToken,
|
||||||
new BoundBinaryOperator(TokenKind.GreaterToken, BoundBinaryOperatorKind.Greater),
|
BoundBinaryOperatorKind.PlusInt,
|
||||||
new BoundBinaryOperator(TokenKind.GreaterOrEqualsToken, BoundBinaryOperatorKind.GreaterOrEquals),
|
TypeSymbol.Int),
|
||||||
new BoundBinaryOperator(TokenKind.EqualsEqualsToken, BoundBinaryOperatorKind.EqualsEquals),
|
|
||||||
new BoundBinaryOperator(TokenKind.TildeEqualsToken, BoundBinaryOperatorKind.TildeEquals),
|
|
||||||
new BoundBinaryOperator(TokenKind.ColonToken, BoundBinaryOperatorKind.Colon),
|
|
||||||
new BoundBinaryOperator(TokenKind.PlusToken, BoundBinaryOperatorKind.Plus),
|
|
||||||
new BoundBinaryOperator(TokenKind.MinusToken, BoundBinaryOperatorKind.Minus),
|
|
||||||
new BoundBinaryOperator(TokenKind.StarToken, BoundBinaryOperatorKind.Star),
|
|
||||||
new BoundBinaryOperator(TokenKind.DotStarToken, BoundBinaryOperatorKind.DotStar),
|
|
||||||
new BoundBinaryOperator(TokenKind.SlashToken, BoundBinaryOperatorKind.Slash),
|
|
||||||
new BoundBinaryOperator(TokenKind.DotSlashToken, BoundBinaryOperatorKind.DotSlash),
|
|
||||||
new BoundBinaryOperator(TokenKind.BackslashToken, BoundBinaryOperatorKind.Backslash),
|
|
||||||
new BoundBinaryOperator(TokenKind.DotBackslashToken, BoundBinaryOperatorKind.DotBackslash),
|
|
||||||
new BoundBinaryOperator(TokenKind.TildeToken, BoundBinaryOperatorKind.Tilde),
|
|
||||||
new BoundBinaryOperator(TokenKind.CaretToken, BoundBinaryOperatorKind.Caret),
|
|
||||||
new BoundBinaryOperator(TokenKind.DotCaretToken, BoundBinaryOperatorKind.DotCaret),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public BoundBinaryOperator(TokenKind syntaxKind, BoundBinaryOperatorKind kind)
|
private static BoundBinaryOperator[] _defaultOperators =
|
||||||
|
{
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.EqualsToken,
|
||||||
|
BoundBinaryOperatorKind.Equals,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.PipePipeToken,
|
||||||
|
BoundBinaryOperatorKind.PipePipe,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.AmpersandAmpersandToken,
|
||||||
|
BoundBinaryOperatorKind.AmpersandAmpersand,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.PipeToken,
|
||||||
|
BoundBinaryOperatorKind.Pipe,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.AmpersandToken,
|
||||||
|
BoundBinaryOperatorKind.Ampersand,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.LessToken,
|
||||||
|
BoundBinaryOperatorKind.Less,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.LessOrEqualsToken,
|
||||||
|
BoundBinaryOperatorKind.LessOrEquals,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.GreaterToken,
|
||||||
|
BoundBinaryOperatorKind.Greater,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.GreaterOrEqualsToken,
|
||||||
|
BoundBinaryOperatorKind.GreaterOrEquals,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.EqualsEqualsToken,
|
||||||
|
BoundBinaryOperatorKind.EqualsEquals,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.TildeEqualsToken,
|
||||||
|
BoundBinaryOperatorKind.TildeEquals,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.ColonToken,
|
||||||
|
BoundBinaryOperatorKind.Colon,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.PlusToken,
|
||||||
|
BoundBinaryOperatorKind.Plus,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.MinusToken,
|
||||||
|
BoundBinaryOperatorKind.Minus,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.StarToken,
|
||||||
|
BoundBinaryOperatorKind.Star,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.DotStarToken,
|
||||||
|
BoundBinaryOperatorKind.DotStar,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.SlashToken,
|
||||||
|
BoundBinaryOperatorKind.Slash,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.DotSlashToken,
|
||||||
|
BoundBinaryOperatorKind.DotSlash,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.BackslashToken,
|
||||||
|
BoundBinaryOperatorKind.Backslash,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.DotBackslashToken,
|
||||||
|
BoundBinaryOperatorKind.DotBackslash,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.TildeToken,
|
||||||
|
BoundBinaryOperatorKind.Tilde,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.CaretToken,
|
||||||
|
BoundBinaryOperatorKind.Caret,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
new BoundBinaryOperator(
|
||||||
|
TokenKind.DotCaretToken,
|
||||||
|
BoundBinaryOperatorKind.DotCaret,
|
||||||
|
TypeSymbol.MObject),
|
||||||
|
};
|
||||||
|
|
||||||
|
public BoundBinaryOperator(
|
||||||
|
TokenKind syntaxKind,
|
||||||
|
BoundBinaryOperatorKind kind,
|
||||||
|
TypeSymbol type)
|
||||||
{
|
{
|
||||||
SyntaxKind = syntaxKind;
|
SyntaxKind = syntaxKind;
|
||||||
Kind = kind;
|
Kind = kind;
|
||||||
|
Left = type;
|
||||||
|
Right = type;
|
||||||
|
Result = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundBinaryOperator(
|
||||||
|
TokenKind syntaxKind,
|
||||||
|
BoundBinaryOperatorKind kind,
|
||||||
|
TypeSymbol operand,
|
||||||
|
TypeSymbol result)
|
||||||
|
{
|
||||||
|
SyntaxKind = syntaxKind;
|
||||||
|
Kind = kind;
|
||||||
|
Left = operand;
|
||||||
|
Right = operand;
|
||||||
|
Result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundBinaryOperator(
|
||||||
|
TokenKind syntaxKind,
|
||||||
|
BoundBinaryOperatorKind kind,
|
||||||
|
TypeSymbol left,
|
||||||
|
TypeSymbol right,
|
||||||
|
TypeSymbol result)
|
||||||
|
{
|
||||||
|
SyntaxKind = syntaxKind;
|
||||||
|
Kind = kind;
|
||||||
|
Left = left;
|
||||||
|
Right = right;
|
||||||
|
Result = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TokenKind SyntaxKind { get; }
|
public TokenKind SyntaxKind { get; }
|
||||||
public BoundBinaryOperatorKind Kind { get; }
|
public BoundBinaryOperatorKind Kind { get; }
|
||||||
|
public TypeSymbol Left { get; }
|
||||||
|
public TypeSymbol Right { get; }
|
||||||
|
public TypeSymbol Result { get; }
|
||||||
|
|
||||||
internal static BoundBinaryOperator? GetOperator(TokenKind kind)
|
internal static BoundBinaryOperator? GetOperator(TokenKind kind, TypeSymbol left, TypeSymbol right)
|
||||||
{
|
{
|
||||||
return _operators.FirstOrDefault(op => op.SyntaxKind == kind);
|
return _specificOperators.FirstOrDefault(op => op.SyntaxKind == kind && op.Left == left && op.Right == right)
|
||||||
|
?? _defaultOperators.FirstOrDefault(op => op.SyntaxKind == kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,5 +25,7 @@
|
|||||||
Tilde,
|
Tilde,
|
||||||
Caret,
|
Caret,
|
||||||
DotCaret,
|
DotCaret,
|
||||||
|
LessInt,
|
||||||
|
PlusInt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,17 @@ namespace Parser.Binding
|
|||||||
return new BoundBlockStatement(syntax, statements);
|
return new BoundBlockStatement(syntax, statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BoundExpressionStatement ExpressionStatement(SyntaxNode syntax, BoundExpression expression)
|
public static BoundConversionExpression Conversion(SyntaxNode syntax, TypeSymbol targetType, BoundExpression expression)
|
||||||
{
|
{
|
||||||
return new BoundExpressionStatement(syntax, expression);
|
return new BoundConversionExpression(syntax, targetType, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundExpressionStatement ExpressionStatement(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression expression,
|
||||||
|
bool discardResult)
|
||||||
|
{
|
||||||
|
return new BoundExpressionStatement(syntax, expression, discardResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BoundIfStatement IfStatement(
|
public static BoundIfStatement IfStatement(
|
||||||
@ -40,6 +48,15 @@ namespace Parser.Binding
|
|||||||
return new BoundIfStatement(syntax, condition, body, elseifClauses, elseClause);
|
return new BoundIfStatement(syntax, condition, body, elseifClauses, elseClause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BoundForStatement ForStatement(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundIdentifierNameExpression loopVariable,
|
||||||
|
BoundExpression loopExpression,
|
||||||
|
BoundStatement body)
|
||||||
|
{
|
||||||
|
return new BoundForStatement(syntax, loopVariable, loopExpression, body);
|
||||||
|
}
|
||||||
|
|
||||||
public static BoundLabelStatement LabelStatement(
|
public static BoundLabelStatement LabelStatement(
|
||||||
SyntaxNode syntax,
|
SyntaxNode syntax,
|
||||||
BoundLabel label)
|
BoundLabel label)
|
||||||
@ -58,10 +75,9 @@ namespace Parser.Binding
|
|||||||
public static BoundBinaryOperationExpression BinaryOperation(
|
public static BoundBinaryOperationExpression BinaryOperation(
|
||||||
SyntaxNode syntax,
|
SyntaxNode syntax,
|
||||||
BoundExpression left,
|
BoundExpression left,
|
||||||
TokenKind kind,
|
BoundBinaryOperator op,
|
||||||
BoundExpression right)
|
BoundExpression right)
|
||||||
{
|
{
|
||||||
var op = BindBinaryOperator(kind);
|
|
||||||
return new BoundBinaryOperationExpression(syntax, left, op, right);
|
return new BoundBinaryOperationExpression(syntax, left, op, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +133,14 @@ namespace Parser.Binding
|
|||||||
return new BoundGotoStatement(syntax, label);
|
return new BoundGotoStatement(syntax, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BoundWhileStatement WhileStatement(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression condition,
|
||||||
|
BoundStatement body)
|
||||||
|
{
|
||||||
|
return new BoundWhileStatement(syntax, condition, body);
|
||||||
|
}
|
||||||
|
|
||||||
public static BoundIdentifierNameExpression Identifier(
|
public static BoundIdentifierNameExpression Identifier(
|
||||||
SyntaxNode syntax,
|
SyntaxNode syntax,
|
||||||
string name)
|
string name)
|
||||||
@ -124,11 +148,18 @@ namespace Parser.Binding
|
|||||||
return new BoundIdentifierNameExpression(syntax, name);
|
return new BoundIdentifierNameExpression(syntax, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BoundNumberLiteralExpression NumberLiteral(
|
public static BoundNumberDoubleLiteralExpression NumberDoubleLiteral(
|
||||||
SyntaxNode syntax,
|
SyntaxNode syntax,
|
||||||
double value)
|
double value)
|
||||||
{
|
{
|
||||||
return new BoundNumberLiteralExpression(syntax, value);
|
return new BoundNumberDoubleLiteralExpression(syntax, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundNumberIntLiteralExpression NumberIntLiteral(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
return new BoundNumberIntLiteralExpression(syntax, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BoundStringLiteralExpression StringLiteral(
|
public static BoundStringLiteralExpression StringLiteral(
|
||||||
@ -146,25 +177,38 @@ namespace Parser.Binding
|
|||||||
return new BoundElseifClause(syntax, condition, body);
|
return new BoundElseifClause(syntax, condition, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BoundTypedVariableDeclaration TypedVariableDeclaration(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
TypedVariableSymbol variable,
|
||||||
|
BoundExpression initializer)
|
||||||
|
{
|
||||||
|
return new BoundTypedVariableDeclaration(syntax, variable, initializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundTypedVariableExpression TypedVariableExpression(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
TypedVariableSymbol variable)
|
||||||
|
{
|
||||||
|
return new BoundTypedVariableExpression(syntax, variable);
|
||||||
|
}
|
||||||
|
|
||||||
public static BoundUnaryOperationExpression UnaryOperation(
|
public static BoundUnaryOperationExpression UnaryOperation(
|
||||||
SyntaxNode syntax,
|
SyntaxNode syntax,
|
||||||
TokenKind kind,
|
BoundUnaryOperator op,
|
||||||
BoundExpression operand)
|
BoundExpression operand)
|
||||||
{
|
{
|
||||||
var op = BindUnaryOperator(kind);
|
|
||||||
return new BoundUnaryOperationExpression(syntax, op, operand);
|
return new BoundUnaryOperationExpression(syntax, op, operand);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundUnaryOperator BindUnaryOperator(TokenKind kind)
|
public static BoundExpression TypedFunctionCall(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
TypedFunctionSymbol function,
|
||||||
|
ImmutableArray<BoundExpression> arguments)
|
||||||
{
|
{
|
||||||
return BoundUnaryOperator.GetOperator(kind)
|
return new BoundTypedFunctionCallExpression(
|
||||||
?? throw new Exception($"Unexpected unary operator kind {kind}.");
|
syntax,
|
||||||
}
|
function,
|
||||||
|
arguments);
|
||||||
private static BoundBinaryOperator BindBinaryOperator(TokenKind kind)
|
|
||||||
{
|
|
||||||
return BoundBinaryOperator.GetOperator(kind)
|
|
||||||
?? throw new Exception($"Unexpected binary operator kind {kind}.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
LabelStatement,
|
LabelStatement,
|
||||||
SwitchStatement,
|
SwitchStatement,
|
||||||
TryCatchStatement,
|
TryCatchStatement,
|
||||||
|
TypedVariableDeclaration,
|
||||||
WhileStatement,
|
WhileStatement,
|
||||||
|
|
||||||
// Expressions
|
// Expressions
|
||||||
@ -33,22 +34,27 @@
|
|||||||
ClassInvokationExpression,
|
ClassInvokationExpression,
|
||||||
CommandExpression,
|
CommandExpression,
|
||||||
CompoundNameExpression,
|
CompoundNameExpression,
|
||||||
|
ConversionExpression,
|
||||||
DoubleQuotedStringLiteralExpression,
|
DoubleQuotedStringLiteralExpression,
|
||||||
EmptyExpression,
|
EmptyExpression,
|
||||||
|
ErrorExpression,
|
||||||
FunctionCallExpression,
|
FunctionCallExpression,
|
||||||
IdentifierNameExpression,
|
IdentifierNameExpression,
|
||||||
IndirectMemberAccessExpression,
|
IndirectMemberAccessExpression,
|
||||||
LambdaExpression,
|
LambdaExpression,
|
||||||
MemberAccessExpression,
|
MemberAccessExpression,
|
||||||
NamedFunctionHandleExpression,
|
NamedFunctionHandleExpression,
|
||||||
NumberLiteralExpression,
|
NumberDoubleLiteralExpression,
|
||||||
|
NumberIntLiteralExpression,
|
||||||
ParenthesizedExpression,
|
ParenthesizedExpression,
|
||||||
StringLiteralExpression,
|
StringLiteralExpression,
|
||||||
|
TypedFunctionCallExpression,
|
||||||
|
TypedVariableExpression,
|
||||||
UnaryOperationExpression,
|
UnaryOperationExpression,
|
||||||
UnquotedStringLiteralExpression,
|
UnquotedStringLiteralExpression,
|
||||||
|
|
||||||
// Parts
|
// Parts
|
||||||
ElseIfClause,
|
ElseIfClause,
|
||||||
ElseClause
|
ElseClause,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,24 +118,40 @@ namespace Parser.Binding
|
|||||||
|
|
||||||
public class BoundExpressionStatement : BoundStatement
|
public class BoundExpressionStatement : BoundStatement
|
||||||
{
|
{
|
||||||
public BoundExpression Expression { get; }
|
public BoundExpressionStatement(SyntaxNode syntax, BoundExpression expression, bool discardResult)
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.ExpressionStatement;
|
|
||||||
|
|
||||||
public BoundExpressionStatement(SyntaxNode syntax, BoundExpression expression)
|
|
||||||
: base(syntax)
|
: base(syntax)
|
||||||
{
|
{
|
||||||
Expression = expression;
|
Expression = expression;
|
||||||
|
DiscardResult = discardResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BoundExpression Expression { get; }
|
||||||
|
|
||||||
|
public bool DiscardResult { get; }
|
||||||
|
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.ExpressionStatement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundForStatement : BoundStatement
|
public class BoundForStatement : BoundStatement
|
||||||
{
|
{
|
||||||
public BoundForStatement(SyntaxNode syntax)
|
public BoundForStatement(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundIdentifierNameExpression loopVariable,
|
||||||
|
BoundExpression loopedExpression,
|
||||||
|
BoundStatement body)
|
||||||
: base(syntax)
|
: base(syntax)
|
||||||
{
|
{
|
||||||
|
LoopVariable = loopVariable;
|
||||||
|
LoopedExpression = loopedExpression;
|
||||||
|
Body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BoundIdentifierNameExpression LoopVariable { get; }
|
||||||
|
|
||||||
|
public BoundExpression LoopedExpression { get; }
|
||||||
|
|
||||||
|
public BoundStatement Body { get; }
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.ForStatement;
|
public override BoundNodeKind Kind => BoundNodeKind.ForStatement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,12 +256,18 @@ namespace Parser.Binding
|
|||||||
|
|
||||||
public class BoundWhileStatement : BoundStatement
|
public class BoundWhileStatement : BoundStatement
|
||||||
{
|
{
|
||||||
public BoundWhileStatement(SyntaxNode syntax)
|
public BoundWhileStatement(SyntaxNode syntax, BoundExpression condition, BoundStatement body)
|
||||||
: base(syntax)
|
: base(syntax)
|
||||||
{
|
{
|
||||||
|
Condition = condition;
|
||||||
|
Body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.WhileStatement;
|
public override BoundNodeKind Kind => BoundNodeKind.WhileStatement;
|
||||||
|
|
||||||
|
public BoundExpression Condition { get; }
|
||||||
|
|
||||||
|
public BoundStatement Body { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class BoundExpression : BoundNode
|
public abstract class BoundExpression : BoundNode
|
||||||
@ -254,6 +276,8 @@ namespace Parser.Binding
|
|||||||
: base(syntax)
|
: base(syntax)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract TypeSymbol Type { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundArrayLiteralExpression : BoundExpression
|
public class BoundArrayLiteralExpression : BoundExpression
|
||||||
@ -264,6 +288,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.ArrayLiteralExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.ArrayLiteralExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundAssignmentExpression : BoundExpression
|
public class BoundAssignmentExpression : BoundExpression
|
||||||
@ -279,6 +305,8 @@ namespace Parser.Binding
|
|||||||
public BoundExpression Right { get; }
|
public BoundExpression Right { get; }
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.AssignmentExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.AssignmentExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => Right.Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundBinaryOperationExpression : BoundExpression
|
public class BoundBinaryOperationExpression : BoundExpression
|
||||||
@ -296,6 +324,8 @@ namespace Parser.Binding
|
|||||||
public BoundExpression Right { get; }
|
public BoundExpression Right { get; }
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.BinaryOperationExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.BinaryOperationExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => Op.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundCellArrayElementAccessExpression : BoundExpression
|
public class BoundCellArrayElementAccessExpression : BoundExpression
|
||||||
@ -306,6 +336,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.CellArrayElementAccessExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.CellArrayElementAccessExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundCellArrayLiteralExpression : BoundExpression
|
public class BoundCellArrayLiteralExpression : BoundExpression
|
||||||
@ -316,6 +348,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.CellArrayLiteralExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.CellArrayLiteralExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundClassInvokationExpression : BoundExpression
|
public class BoundClassInvokationExpression : BoundExpression
|
||||||
@ -326,6 +360,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.ClassInvokationExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.ClassInvokationExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundCommandExpression : BoundExpression
|
public class BoundCommandExpression : BoundExpression
|
||||||
@ -336,6 +372,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.CommandExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.CommandExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundCompoundNameExpression : BoundExpression
|
public class BoundCompoundNameExpression : BoundExpression
|
||||||
@ -346,6 +384,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.CompoundNameExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.CompoundNameExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundDoubleQuotedStringLiteralExpression : BoundExpression
|
public class BoundDoubleQuotedStringLiteralExpression : BoundExpression
|
||||||
@ -356,6 +396,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.DoubleQuotedStringLiteralExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.DoubleQuotedStringLiteralExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundEmptyExpression : BoundExpression
|
public class BoundEmptyExpression : BoundExpression
|
||||||
@ -366,6 +408,20 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.EmptyExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.EmptyExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => TypeSymbol.Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoundErrorExpression : BoundExpression
|
||||||
|
{
|
||||||
|
public BoundErrorExpression(SyntaxNode syntax)
|
||||||
|
: base(syntax)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.ErrorExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => TypeSymbol.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundFunctionCallExpression : BoundExpression
|
public class BoundFunctionCallExpression : BoundExpression
|
||||||
@ -380,6 +436,27 @@ namespace Parser.Binding
|
|||||||
public BoundExpression Name { get; }
|
public BoundExpression Name { get; }
|
||||||
public ImmutableArray<BoundExpression> Arguments { get; }
|
public ImmutableArray<BoundExpression> Arguments { get; }
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.FunctionCallExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.FunctionCallExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => TypeSymbol.MObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoundTypedFunctionCallExpression : BoundExpression
|
||||||
|
{
|
||||||
|
public BoundTypedFunctionCallExpression(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
TypedFunctionSymbol function,
|
||||||
|
ImmutableArray<BoundExpression> arguments)
|
||||||
|
: base(syntax)
|
||||||
|
{
|
||||||
|
Function = function;
|
||||||
|
Arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypedFunctionSymbol Function { get; }
|
||||||
|
public ImmutableArray<BoundExpression> Arguments { get; }
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.TypedFunctionCallExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => Function.ReturnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundIdentifierNameExpression : BoundExpression
|
public class BoundIdentifierNameExpression : BoundExpression
|
||||||
@ -392,6 +469,8 @@ namespace Parser.Binding
|
|||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.IdentifierNameExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.IdentifierNameExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => TypeSymbol.MObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundIndirectMemberAccessExpression : BoundExpression
|
public class BoundIndirectMemberAccessExpression : BoundExpression
|
||||||
@ -402,6 +481,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.IndirectMemberAccessExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.IndirectMemberAccessExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundLambdaExpression : BoundExpression
|
public class BoundLambdaExpression : BoundExpression
|
||||||
@ -412,6 +493,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.LambdaExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.LambdaExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundMemberAccessExpression : BoundExpression
|
public class BoundMemberAccessExpression : BoundExpression
|
||||||
@ -422,6 +505,8 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.MemberAccessExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.MemberAccessExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundNamedFunctionHandleExpression : BoundExpression
|
public class BoundNamedFunctionHandleExpression : BoundExpression
|
||||||
@ -432,18 +517,43 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.NamedFunctionHandleExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.NamedFunctionHandleExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundNumberLiteralExpression : BoundExpression
|
public abstract class BoundNumberLiteralExpression : BoundExpression
|
||||||
{
|
{
|
||||||
public BoundNumberLiteralExpression(SyntaxNode syntax, double value)
|
protected BoundNumberLiteralExpression(SyntaxNode syntax) : base(syntax)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoundNumberDoubleLiteralExpression : BoundNumberLiteralExpression
|
||||||
|
{
|
||||||
|
public BoundNumberDoubleLiteralExpression(SyntaxNode syntax, double value)
|
||||||
: base(syntax)
|
: base(syntax)
|
||||||
{
|
{
|
||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double Value { get; }
|
public double Value { get; }
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.NumberLiteralExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.NumberDoubleLiteralExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => TypeSymbol.Double;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoundNumberIntLiteralExpression : BoundNumberLiteralExpression
|
||||||
|
{
|
||||||
|
public BoundNumberIntLiteralExpression(SyntaxNode syntax, int value)
|
||||||
|
: base(syntax)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Value { get; }
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.NumberIntLiteralExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => TypeSymbol.Int;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundStringLiteralExpression : BoundExpression
|
public class BoundStringLiteralExpression : BoundExpression
|
||||||
@ -456,6 +566,39 @@ namespace Parser.Binding
|
|||||||
|
|
||||||
public string Value { get; }
|
public string Value { get; }
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.StringLiteralExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.StringLiteralExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => TypeSymbol.String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoundTypedVariableDeclaration : BoundStatement
|
||||||
|
{
|
||||||
|
public BoundTypedVariableDeclaration(SyntaxNode syntax, TypedVariableSymbol variable, BoundExpression initializer)
|
||||||
|
: base(syntax)
|
||||||
|
{
|
||||||
|
Variable = variable;
|
||||||
|
Initializer = initializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypedVariableSymbol Variable { get; }
|
||||||
|
|
||||||
|
public BoundExpression Initializer { get; }
|
||||||
|
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.TypedVariableDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoundTypedVariableExpression : BoundExpression
|
||||||
|
{
|
||||||
|
public BoundTypedVariableExpression(SyntaxNode syntax, TypedVariableSymbol variable)
|
||||||
|
: base(syntax)
|
||||||
|
{
|
||||||
|
Variable = variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypedVariableSymbol Variable { get; }
|
||||||
|
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.TypedVariableExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => Variable.Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundUnaryOperationExpression : BoundExpression
|
public class BoundUnaryOperationExpression : BoundExpression
|
||||||
@ -471,6 +614,8 @@ namespace Parser.Binding
|
|||||||
|
|
||||||
public BoundUnaryOperator Op { get; }
|
public BoundUnaryOperator Op { get; }
|
||||||
public BoundExpression Operand { get; }
|
public BoundExpression Operand { get; }
|
||||||
|
|
||||||
|
public override TypeSymbol Type => Op.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundUnquotedStringLiteralExpression : BoundExpression
|
public class BoundUnquotedStringLiteralExpression : BoundExpression
|
||||||
@ -481,6 +626,26 @@ namespace Parser.Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.UnquotedStringLiteralExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.UnquotedStringLiteralExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoundConversionExpression : BoundExpression
|
||||||
|
{
|
||||||
|
public BoundConversionExpression(SyntaxNode syntax, TypeSymbol targetType, BoundExpression expression)
|
||||||
|
: base(syntax)
|
||||||
|
{
|
||||||
|
TargetType = targetType;
|
||||||
|
Expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeSymbol TargetType { get; }
|
||||||
|
|
||||||
|
public BoundExpression Expression { get; }
|
||||||
|
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.ConversionExpression;
|
||||||
|
|
||||||
|
public override TypeSymbol Type => TargetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundElseifClause : BoundNode
|
public class BoundElseifClause : BoundNode
|
||||||
|
@ -38,6 +38,8 @@ namespace Parser.Binding
|
|||||||
RewriteSwitchStatement((BoundSwitchStatement)node),
|
RewriteSwitchStatement((BoundSwitchStatement)node),
|
||||||
BoundNodeKind.TryCatchStatement =>
|
BoundNodeKind.TryCatchStatement =>
|
||||||
RewriteTryCatchStatement((BoundTryCatchStatement)node),
|
RewriteTryCatchStatement((BoundTryCatchStatement)node),
|
||||||
|
BoundNodeKind.TypedVariableDeclaration =>
|
||||||
|
RewriteTypedVariableDeclaration((BoundTypedVariableDeclaration)node),
|
||||||
BoundNodeKind.WhileStatement =>
|
BoundNodeKind.WhileStatement =>
|
||||||
RewriteWhileStatement((BoundWhileStatement)node),
|
RewriteWhileStatement((BoundWhileStatement)node),
|
||||||
_ =>
|
_ =>
|
||||||
@ -45,6 +47,11 @@ namespace Parser.Binding
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual BoundStatement RewriteTypedVariableDeclaration(BoundTypedVariableDeclaration node)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual BoundStatement RewriteGotoStatement(BoundGotoStatement node)
|
public virtual BoundStatement RewriteGotoStatement(BoundGotoStatement node)
|
||||||
{
|
{
|
||||||
return node;
|
return node;
|
||||||
@ -63,7 +70,9 @@ namespace Parser.Binding
|
|||||||
|
|
||||||
public virtual BoundStatement RewriteWhileStatement(BoundWhileStatement node)
|
public virtual BoundStatement RewriteWhileStatement(BoundWhileStatement node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var condition = RewriteExpression(node.Condition);
|
||||||
|
var body = RewriteStatement(node.Body);
|
||||||
|
return WhileStatement(node.Syntax, condition, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundStatement RewriteTryCatchStatement(BoundTryCatchStatement node)
|
public virtual BoundStatement RewriteTryCatchStatement(BoundTryCatchStatement node)
|
||||||
@ -136,7 +145,7 @@ namespace Parser.Binding
|
|||||||
|
|
||||||
public virtual BoundStatement RewriteForStatement(BoundForStatement node)
|
public virtual BoundStatement RewriteForStatement(BoundForStatement node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundStatement RewriteExpressionStatement(BoundExpressionStatement node)
|
public virtual BoundStatement RewriteExpressionStatement(BoundExpressionStatement node)
|
||||||
@ -147,7 +156,7 @@ namespace Parser.Binding
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExpressionStatement(node.Syntax, expression);
|
return ExpressionStatement(node.Syntax, expression, node.DiscardResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundStatement RewriteEmptyStatement(BoundEmptyStatement node)
|
public virtual BoundStatement RewriteEmptyStatement(BoundEmptyStatement node)
|
||||||
@ -220,6 +229,8 @@ namespace Parser.Binding
|
|||||||
RewriteCommandExpression((BoundCommandExpression)node),
|
RewriteCommandExpression((BoundCommandExpression)node),
|
||||||
BoundNodeKind.CompoundNameExpression =>
|
BoundNodeKind.CompoundNameExpression =>
|
||||||
RewriteCompoundNameExpression((BoundCompoundNameExpression)node),
|
RewriteCompoundNameExpression((BoundCompoundNameExpression)node),
|
||||||
|
BoundNodeKind.ConversionExpression =>
|
||||||
|
RewriteConversionExpression((BoundConversionExpression)node),
|
||||||
BoundNodeKind.DoubleQuotedStringLiteralExpression =>
|
BoundNodeKind.DoubleQuotedStringLiteralExpression =>
|
||||||
RewriteDoubleQuotedStringLiteralExpression((BoundDoubleQuotedStringLiteralExpression)node),
|
RewriteDoubleQuotedStringLiteralExpression((BoundDoubleQuotedStringLiteralExpression)node),
|
||||||
BoundNodeKind.EmptyExpression =>
|
BoundNodeKind.EmptyExpression =>
|
||||||
@ -236,10 +247,14 @@ namespace Parser.Binding
|
|||||||
RewriteMemberAccessExpression((BoundMemberAccessExpression)node),
|
RewriteMemberAccessExpression((BoundMemberAccessExpression)node),
|
||||||
BoundNodeKind.NamedFunctionHandleExpression =>
|
BoundNodeKind.NamedFunctionHandleExpression =>
|
||||||
RewriteNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
RewriteNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
||||||
BoundNodeKind.NumberLiteralExpression =>
|
BoundNodeKind.NumberDoubleLiteralExpression =>
|
||||||
RewriteNumberLiteralExpression((BoundNumberLiteralExpression)node),
|
RewriteNumberDoubleLiteralExpression((BoundNumberDoubleLiteralExpression)node),
|
||||||
|
BoundNodeKind.NumberIntLiteralExpression =>
|
||||||
|
RewriteNumberIntLiteralExpression((BoundNumberIntLiteralExpression)node),
|
||||||
BoundNodeKind.StringLiteralExpression =>
|
BoundNodeKind.StringLiteralExpression =>
|
||||||
RewriteStringLiteralExpression((BoundStringLiteralExpression)node),
|
RewriteStringLiteralExpression((BoundStringLiteralExpression)node),
|
||||||
|
BoundNodeKind.TypedVariableExpression =>
|
||||||
|
RewriteTypedVariableExpression((BoundTypedVariableExpression)node),
|
||||||
BoundNodeKind.UnaryOperationExpression =>
|
BoundNodeKind.UnaryOperationExpression =>
|
||||||
RewriteUnaryOperationExpression((BoundUnaryOperationExpression)node),
|
RewriteUnaryOperationExpression((BoundUnaryOperationExpression)node),
|
||||||
BoundNodeKind.UnquotedStringLiteralExpression =>
|
BoundNodeKind.UnquotedStringLiteralExpression =>
|
||||||
@ -249,6 +264,17 @@ namespace Parser.Binding
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual BoundExpression RewriteConversionExpression(BoundConversionExpression node)
|
||||||
|
{
|
||||||
|
var operand = RewriteExpression(node.Expression);
|
||||||
|
return Conversion(node.Syntax, node.TargetType, operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual BoundExpression RewriteTypedVariableExpression(BoundTypedVariableExpression node)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual BoundExpression RewriteUnquotedStringLiteralExpression(BoundUnquotedStringLiteralExpression node)
|
public virtual BoundExpression RewriteUnquotedStringLiteralExpression(BoundUnquotedStringLiteralExpression node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@ -265,7 +291,12 @@ namespace Parser.Binding
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundExpression RewriteNumberLiteralExpression(BoundNumberLiteralExpression node)
|
public virtual BoundExpression RewriteNumberDoubleLiteralExpression(BoundNumberDoubleLiteralExpression node)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual BoundExpression RewriteNumberIntLiteralExpression(BoundNumberIntLiteralExpression node)
|
||||||
{
|
{
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,42 @@
|
|||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Parser.Binding
|
namespace Parser.Binding
|
||||||
{
|
{
|
||||||
public class BoundUnaryOperator
|
public class BoundUnaryOperator
|
||||||
{
|
{
|
||||||
private static BoundUnaryOperator[] _operators =
|
private static BoundUnaryOperator[] _specificOperators = Array.Empty<BoundUnaryOperator>();
|
||||||
|
|
||||||
|
private static BoundUnaryOperator[] _defaultOperators =
|
||||||
{
|
{
|
||||||
new BoundUnaryOperator(TokenKind.MinusToken, BoundUnaryOperatorKind.Minus),
|
new BoundUnaryOperator(TokenKind.MinusToken, BoundUnaryOperatorKind.Minus, TypeSymbol.MObject),
|
||||||
};
|
};
|
||||||
|
|
||||||
public BoundUnaryOperator(TokenKind syntaxKind, BoundUnaryOperatorKind kind)
|
public BoundUnaryOperator(TokenKind syntaxKind, BoundUnaryOperatorKind kind, TypeSymbol type)
|
||||||
{
|
{
|
||||||
SyntaxKind = syntaxKind;
|
SyntaxKind = syntaxKind;
|
||||||
Kind = kind;
|
Kind = kind;
|
||||||
|
Operand = type;
|
||||||
|
Result = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundUnaryOperator(TokenKind syntaxKind, BoundUnaryOperatorKind kind, TypeSymbol operand, TypeSymbol result)
|
||||||
|
{
|
||||||
|
SyntaxKind = syntaxKind;
|
||||||
|
Kind = kind;
|
||||||
|
Operand = operand;
|
||||||
|
Result = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TokenKind SyntaxKind { get; }
|
public TokenKind SyntaxKind { get; }
|
||||||
public BoundUnaryOperatorKind Kind { get; }
|
public BoundUnaryOperatorKind Kind { get; }
|
||||||
|
public TypeSymbol Operand { get; }
|
||||||
|
public TypeSymbol Result { get; }
|
||||||
|
|
||||||
internal static BoundUnaryOperator? GetOperator(TokenKind kind)
|
internal static BoundUnaryOperator? GetOperator(TokenKind kind, TypeSymbol operand)
|
||||||
{
|
{
|
||||||
return _operators.FirstOrDefault(op => op.SyntaxKind == kind);
|
return _specificOperators.FirstOrDefault(op => op.SyntaxKind == kind && op.Operand == operand)
|
||||||
|
?? _defaultOperators.FirstOrDefault(op => op.SyntaxKind == kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
Parser/Binding/Conversion.cs
Normal file
39
Parser/Binding/Conversion.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
namespace Parser.Binding
|
||||||
|
{
|
||||||
|
internal class Conversion
|
||||||
|
{
|
||||||
|
public static Conversion None = new Conversion(exists: false, isIdentity: false);
|
||||||
|
public static Conversion Identity = new Conversion(exists: true, isIdentity: true);
|
||||||
|
public static Conversion Implicit = new Conversion(exists: true, isIdentity: false);
|
||||||
|
|
||||||
|
private Conversion(bool exists, bool isIdentity)
|
||||||
|
{
|
||||||
|
Exists = exists;
|
||||||
|
IsIdentity = isIdentity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Exists { get; }
|
||||||
|
|
||||||
|
public bool IsIdentity { get; }
|
||||||
|
|
||||||
|
public static Conversion Classify(TypeSymbol from, TypeSymbol to)
|
||||||
|
{
|
||||||
|
if (from == to)
|
||||||
|
{
|
||||||
|
return Identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to == TypeSymbol.MObject)
|
||||||
|
{
|
||||||
|
return Implicit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to == TypeSymbol.Boolean)
|
||||||
|
{
|
||||||
|
return Implicit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
Parser/Binding/TypeSymbol.cs
Normal file
26
Parser/Binding/TypeSymbol.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
namespace Parser.Binding
|
||||||
|
{
|
||||||
|
public class TypeSymbol
|
||||||
|
{
|
||||||
|
public static readonly TypeSymbol Error = new TypeSymbol("error");
|
||||||
|
public static readonly TypeSymbol Null = new TypeSymbol("null");
|
||||||
|
public static readonly TypeSymbol Boolean = new TypeSymbol("bool");
|
||||||
|
public static readonly TypeSymbol Double = new TypeSymbol("double");
|
||||||
|
public static readonly TypeSymbol Int = new TypeSymbol("int");
|
||||||
|
public static readonly TypeSymbol String = new TypeSymbol("string");
|
||||||
|
public static readonly TypeSymbol MObject = new TypeSymbol("mobject");
|
||||||
|
public static readonly TypeSymbol Void = new TypeSymbol("void");
|
||||||
|
|
||||||
|
private TypeSymbol(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
Parser/Binding/TypedFunctionSymbol.cs
Normal file
23
Parser/Binding/TypedFunctionSymbol.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Parser.Binding
|
||||||
|
{
|
||||||
|
public class TypedFunctionSymbol
|
||||||
|
{
|
||||||
|
public TypedFunctionSymbol(
|
||||||
|
string name,
|
||||||
|
ImmutableArray<TypedParameterSymbol> parameters,
|
||||||
|
TypeSymbol returnType)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Parameters = parameters;
|
||||||
|
ReturnType = returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public ImmutableArray<TypedParameterSymbol> Parameters { get; }
|
||||||
|
|
||||||
|
public TypeSymbol ReturnType { get; }
|
||||||
|
}
|
||||||
|
}
|
14
Parser/Binding/TypedParameterSymbol.cs
Normal file
14
Parser/Binding/TypedParameterSymbol.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace Parser.Binding
|
||||||
|
{
|
||||||
|
public class TypedParameterSymbol
|
||||||
|
{
|
||||||
|
public TypedParameterSymbol(string name, TypeSymbol type)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public TypeSymbol Type { get; }
|
||||||
|
}
|
||||||
|
}
|
15
Parser/Binding/TypedVariableSymbol.cs
Normal file
15
Parser/Binding/TypedVariableSymbol.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace Parser.Binding
|
||||||
|
{
|
||||||
|
public class TypedVariableSymbol
|
||||||
|
{
|
||||||
|
public TypedVariableSymbol(string name, TypeSymbol type)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public TypeSymbol Type { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using Parser.Binding;
|
using Parser.Binding;
|
||||||
|
using Parser.Emitting;
|
||||||
|
|
||||||
namespace Parser
|
namespace Parser
|
||||||
{
|
{
|
||||||
@ -16,6 +17,13 @@ namespace Parser
|
|||||||
return new Compilation(syntaxTree);
|
return new Compilation(syntaxTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Emit(string[] references, string outputPath)
|
||||||
|
{
|
||||||
|
var emitter = new Emitter();
|
||||||
|
var boundProgram = GetBoundProgram();
|
||||||
|
emitter.Emit(boundProgram, references, outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
private BoundProgram GetBoundProgram()
|
private BoundProgram GetBoundProgram()
|
||||||
{
|
{
|
||||||
return Binder.BindProgram(_syntaxTree);
|
return Binder.BindProgram(_syntaxTree);
|
||||||
|
840
Parser/Emitting/Emitter.cs
Normal file
840
Parser/Emitting/Emitter.cs
Normal file
@ -0,0 +1,840 @@
|
|||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
using Mono.Cecil.Rocks;
|
||||||
|
using Parser.Binding;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Parser.Emitting
|
||||||
|
{
|
||||||
|
public static class BuiltInFunctions
|
||||||
|
{
|
||||||
|
public static readonly TypedFunctionSymbol Disp = new TypedFunctionSymbol(
|
||||||
|
"disp",
|
||||||
|
ImmutableArray.Create(
|
||||||
|
new TypedParameterSymbol("text", TypeSymbol.MObject)),
|
||||||
|
TypeSymbol.Void);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Emitter
|
||||||
|
{
|
||||||
|
private Dictionary<string, TypeReference> _knownTypes = new Dictionary<string, TypeReference>();
|
||||||
|
private Dictionary<TypeSymbol, TypeReference> _resolvedTypes = new Dictionary<TypeSymbol, TypeReference>();
|
||||||
|
private Dictionary<string, MethodInterfaceDescription> _functions = new Dictionary<string, MethodInterfaceDescription>();
|
||||||
|
private MethodReference? _consoleWriteLineReference;
|
||||||
|
private MethodReference? _dispReference;
|
||||||
|
private MethodReference? _lenReference;
|
||||||
|
private MethodReference? _arraySliceReference;
|
||||||
|
private MethodReference? _mObjectToBool;
|
||||||
|
private MethodReference? _stringToMObject;
|
||||||
|
private MethodReference? _doubleToMObject;
|
||||||
|
private MethodReference? _intToMObject;
|
||||||
|
private MethodReference? _getItemFromDictionary;
|
||||||
|
private MethodReference? _putItemIntoDictionary;
|
||||||
|
private TypeReference? _mObjectType;
|
||||||
|
private ArrayType? _mObjectArrayType;
|
||||||
|
private Dictionary<string, VariableDefinition> _currentOutputVariables = new Dictionary<string, VariableDefinition>();
|
||||||
|
private VariableDefinition? _currentLocals = null;
|
||||||
|
private TypeSpecification? _stringMObjectDictionary = null;
|
||||||
|
private MethodReference? _dictionaryCtorReference = null;
|
||||||
|
private Dictionary<BoundBinaryOperatorKind, MethodReference> _binaryOperations = new Dictionary<BoundBinaryOperatorKind, MethodReference>();
|
||||||
|
private Dictionary<BoundUnaryOperatorKind, MethodReference> _unaryOperations = new Dictionary<BoundUnaryOperatorKind, MethodReference>();
|
||||||
|
private Dictionary<BoundLabel, int> _labels = new Dictionary<BoundLabel, int>();
|
||||||
|
private Dictionary<int, BoundLabel> _forwardLabelsToFix = new Dictionary<int, BoundLabel>();
|
||||||
|
private Dictionary<TypedVariableSymbol, VariableDefinition> _typedLocals = new Dictionary<TypedVariableSymbol, VariableDefinition>();
|
||||||
|
private Dictionary<TypedFunctionSymbol, MethodReference> _builtInFunctions = new Dictionary<TypedFunctionSymbol, MethodReference>();
|
||||||
|
|
||||||
|
private static TypeReference ResolveAndImportType(
|
||||||
|
string typeName,
|
||||||
|
List<AssemblyDefinition> assemblies,
|
||||||
|
AssemblyDefinition assemblyDefinition)
|
||||||
|
{
|
||||||
|
var foundTypes = assemblies.SelectMany(a => a.Modules)
|
||||||
|
.SelectMany(m => m.Types)
|
||||||
|
.Where(t => t.FullName == typeName)
|
||||||
|
.ToArray();
|
||||||
|
if (foundTypes.Length == 1)
|
||||||
|
{
|
||||||
|
var typeReference = assemblyDefinition.MainModule.ImportReference(foundTypes[0]);
|
||||||
|
return typeReference;
|
||||||
|
}
|
||||||
|
else if (foundTypes.Length == 0)
|
||||||
|
{
|
||||||
|
throw new Exception($"Cannot find type {typeName}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"Ambiguous type {typeName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodReference ResolveAndImportMethod(
|
||||||
|
string typeName,
|
||||||
|
string methodName,
|
||||||
|
string[] parameterTypeNames,
|
||||||
|
List<AssemblyDefinition> assemblies,
|
||||||
|
AssemblyDefinition assemblyDefinition)
|
||||||
|
{
|
||||||
|
var foundTypes = assemblies.SelectMany(a => a.Modules)
|
||||||
|
.SelectMany(m => m.Types)
|
||||||
|
.Where(t => t.FullName == typeName)
|
||||||
|
.ToArray();
|
||||||
|
if (foundTypes.Length == 1)
|
||||||
|
{
|
||||||
|
var foundType = foundTypes[0];
|
||||||
|
var methods = foundType.Methods.Where(m => m.Name == methodName);
|
||||||
|
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
if (method.Parameters.Count != parameterTypeNames.Length)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var allParametersMatch = true;
|
||||||
|
|
||||||
|
for (var i = 0; i < parameterTypeNames.Length; i++)
|
||||||
|
{
|
||||||
|
if (method.Parameters[i].ParameterType.FullName != parameterTypeNames[i])
|
||||||
|
{
|
||||||
|
allParametersMatch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allParametersMatch)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return assemblyDefinition.MainModule.ImportReference(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception($"Required method {typeName}.{methodName} not found.");
|
||||||
|
}
|
||||||
|
else if (foundTypes.Length == 0)
|
||||||
|
{
|
||||||
|
throw new Exception($"Required type {typeName} not found.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"Required type {typeName} is ambiguous.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Emit(BoundProgram program, string[] references, string outputFileName)
|
||||||
|
{
|
||||||
|
var assemblies = new List<AssemblyDefinition>();
|
||||||
|
|
||||||
|
foreach (var reference in references)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var assembly = AssemblyDefinition.ReadAssembly(reference);
|
||||||
|
assemblies.Add(assembly);
|
||||||
|
}
|
||||||
|
catch (BadImageFormatException)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid reference '{reference}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var moduleName = Path.GetFileNameWithoutExtension(outputFileName);
|
||||||
|
var assemblyName = new AssemblyNameDefinition(
|
||||||
|
name: moduleName,
|
||||||
|
version: new Version(1, 0));
|
||||||
|
var assemblyDefinition = AssemblyDefinition.CreateAssembly(
|
||||||
|
assemblyName: assemblyName,
|
||||||
|
moduleName: moduleName,
|
||||||
|
kind: ModuleKind.Console);
|
||||||
|
var builtInTypes = new[]
|
||||||
|
{
|
||||||
|
"System.Int32",
|
||||||
|
"System.Object",
|
||||||
|
"System.Void",
|
||||||
|
"System.String",
|
||||||
|
"System.Collections.Generic.Dictionary`2",
|
||||||
|
"Parser.Objects.MObject"
|
||||||
|
};
|
||||||
|
|
||||||
|
var typeSymbolToKnownType = new Dictionary<TypeSymbol, string>
|
||||||
|
{
|
||||||
|
[TypeSymbol.Int] = "System.Int32",
|
||||||
|
[TypeSymbol.MObject] = "Parser.Objects.MObject",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Resolve built-in types and methods.
|
||||||
|
foreach (var typeName in builtInTypes)
|
||||||
|
{
|
||||||
|
var typeReference = ResolveAndImportType(typeName, assemblies, assemblyDefinition);
|
||||||
|
_knownTypes.Add(typeName, typeReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (typeSymbol, knownTypeName) in typeSymbolToKnownType)
|
||||||
|
{
|
||||||
|
_resolvedTypes.Add(typeSymbol, _knownTypes[knownTypeName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var objectType = _knownTypes["System.Object"];
|
||||||
|
var voidType = _knownTypes["System.Void"];
|
||||||
|
var stringType = _knownTypes["System.String"];
|
||||||
|
var dictionaryType = _knownTypes["System.Collections.Generic.Dictionary`2"];
|
||||||
|
_mObjectType = _knownTypes["Parser.Objects.MObject"];
|
||||||
|
_mObjectArrayType = _mObjectType.MakeArrayType();
|
||||||
|
var stringMObjectDictionary = new GenericInstanceType(dictionaryType);
|
||||||
|
stringMObjectDictionary.GenericArguments.Add(stringType);
|
||||||
|
stringMObjectDictionary.GenericArguments.Add(_mObjectType);
|
||||||
|
_stringMObjectDictionary = stringMObjectDictionary;
|
||||||
|
_dictionaryCtorReference = ResolveAndImportMethod(
|
||||||
|
typeName: "System.Collections.Generic.Dictionary`2",
|
||||||
|
methodName: ".ctor",
|
||||||
|
parameterTypeNames: Array.Empty<string>(),
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
_dictionaryCtorReference.DeclaringType = _stringMObjectDictionary;
|
||||||
|
_getItemFromDictionary = ResolveAndImportMethod(
|
||||||
|
typeName: "System.Collections.Generic.Dictionary`2",
|
||||||
|
methodName: "get_Item",
|
||||||
|
parameterTypeNames: new[] { "TKey" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
_getItemFromDictionary.DeclaringType = _stringMObjectDictionary;
|
||||||
|
_putItemIntoDictionary = ResolveAndImportMethod(
|
||||||
|
typeName: "System.Collections.Generic.Dictionary`2",
|
||||||
|
methodName: "set_Item",
|
||||||
|
parameterTypeNames: new[] { "TKey", "TValue" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
_putItemIntoDictionary.DeclaringType = _stringMObjectDictionary;
|
||||||
|
|
||||||
|
_consoleWriteLineReference = ResolveAndImportMethod(
|
||||||
|
typeName: "System.Console",
|
||||||
|
methodName: "WriteLine",
|
||||||
|
parameterTypeNames: new[] { "System.Object" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_dispReference = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MHelpers",
|
||||||
|
methodName: "Disp",
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_lenReference = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MHelpers",
|
||||||
|
methodName: "Len",
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_arraySliceReference = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MOperations",
|
||||||
|
methodName: "ArraySlice",
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject", "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_mObjectToBool = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MHelpers",
|
||||||
|
methodName: "ToBool",
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_stringToMObject = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.Objects.MObject",
|
||||||
|
methodName: "CreateCharArray",
|
||||||
|
parameterTypeNames: new[] { "System.String" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_doubleToMObject = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.Objects.MObject",
|
||||||
|
methodName: "CreateDoubleNumber",
|
||||||
|
parameterTypeNames: new[] { "System.Double" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_intToMObject = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.Objects.MObject",
|
||||||
|
methodName: "CreateIntNumber",
|
||||||
|
parameterTypeNames: new[] { "System.Int32" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
var binaryOperationNames = new Dictionary<BoundBinaryOperatorKind, string>
|
||||||
|
{
|
||||||
|
[BoundBinaryOperatorKind.Colon] = "Colon",
|
||||||
|
[BoundBinaryOperatorKind.Plus] = "Plus",
|
||||||
|
[BoundBinaryOperatorKind.Minus] = "Minus",
|
||||||
|
[BoundBinaryOperatorKind.Star] = "Star",
|
||||||
|
[BoundBinaryOperatorKind.Slash] = "Slash",
|
||||||
|
[BoundBinaryOperatorKind.Greater] = "Greater",
|
||||||
|
[BoundBinaryOperatorKind.GreaterOrEquals] = "GreaterOrEquals",
|
||||||
|
[BoundBinaryOperatorKind.Less] = "Less",
|
||||||
|
[BoundBinaryOperatorKind.LessOrEquals] = "LessOrEquals",
|
||||||
|
};
|
||||||
|
|
||||||
|
var unaryOperationNames = new Dictionary<BoundUnaryOperatorKind, string>
|
||||||
|
{
|
||||||
|
[BoundUnaryOperatorKind.Minus] = "Minus",
|
||||||
|
};
|
||||||
|
|
||||||
|
_builtInFunctions.Add(
|
||||||
|
BuiltInFunctions.Disp,
|
||||||
|
_dispReference);
|
||||||
|
|
||||||
|
foreach (var (op, opName) in binaryOperationNames)
|
||||||
|
{
|
||||||
|
_binaryOperations[op] = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MOperations",
|
||||||
|
methodName: opName,
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject", "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (op, opName) in unaryOperationNames)
|
||||||
|
{
|
||||||
|
_unaryOperations[op] = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MOperations",
|
||||||
|
methodName: opName,
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create type.
|
||||||
|
var typeDefinition = new TypeDefinition(
|
||||||
|
@namespace: "",
|
||||||
|
name: "Program",
|
||||||
|
attributes: TypeAttributes.Abstract | TypeAttributes.Sealed,
|
||||||
|
baseType: objectType);
|
||||||
|
assemblyDefinition.MainModule.Types.Add(typeDefinition);
|
||||||
|
|
||||||
|
// Generate method definitions for all functions first.
|
||||||
|
foreach (var (name, body) in program.Functions)
|
||||||
|
{
|
||||||
|
var methodDefinition = new MethodDefinition(
|
||||||
|
name: name.Name,
|
||||||
|
attributes: MethodAttributes.Static | MethodAttributes.Private,
|
||||||
|
returnType: body.OutputDescription.Length == 0 ? voidType : _mObjectArrayType);
|
||||||
|
if (body.InputDescription.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (var inputDescription in body.InputDescription)
|
||||||
|
{
|
||||||
|
var parameter = new ParameterDefinition(
|
||||||
|
name: inputDescription.Name,
|
||||||
|
attributes: ParameterAttributes.None,
|
||||||
|
parameterType: _mObjectType);
|
||||||
|
methodDefinition.Parameters.Add(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_functions[name.Name] = new MethodInterfaceDescription(
|
||||||
|
inputDescription: body.InputDescription,
|
||||||
|
outputDescription: body.OutputDescription,
|
||||||
|
method: methodDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit functions.
|
||||||
|
foreach (var (name, body) in program.Functions)
|
||||||
|
{
|
||||||
|
var methodDefinition = _functions[name.Name];
|
||||||
|
EmitFunction(body, methodDefinition.Method);
|
||||||
|
typeDefinition.Methods.Add(methodDefinition.Method);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set entry point.
|
||||||
|
if (program.ScriptFunction is { } scriptFunction)
|
||||||
|
{
|
||||||
|
assemblyDefinition.EntryPoint = _functions[scriptFunction.Name].Method;
|
||||||
|
}
|
||||||
|
else if (program.MainFunction is { } mainFunction)
|
||||||
|
{
|
||||||
|
assemblyDefinition.EntryPoint = _functions[mainFunction.Name].Method;
|
||||||
|
}
|
||||||
|
|
||||||
|
assemblyDefinition.Write(outputFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitFunction(LoweredFunction function, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
|
||||||
|
_labels.Clear();
|
||||||
|
_forwardLabelsToFix.Clear();
|
||||||
|
_typedLocals.Clear();
|
||||||
|
|
||||||
|
// Local #0 is the dictionary with actual local variables.
|
||||||
|
_currentLocals = new VariableDefinition(_stringMObjectDictionary);
|
||||||
|
ilProcessor.Body.Variables.Add(_currentLocals);
|
||||||
|
ilProcessor.Emit(OpCodes.Newobj, _dictionaryCtorReference);
|
||||||
|
ilProcessor.Emit(OpCodes.Stloc_0);
|
||||||
|
var counter = 0;
|
||||||
|
foreach (var inputDescription in function.InputDescription)
|
||||||
|
{
|
||||||
|
var name = inputDescription.Name;
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldstr, name);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldarg, methodDefinition.Parameters[counter]);
|
||||||
|
ilProcessor.Emit(OpCodes.Callvirt, _putItemIntoDictionary);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The following locals are "output variables".
|
||||||
|
_currentOutputVariables.Clear();
|
||||||
|
if (function.OutputDescription.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (var outputDescription in function.OutputDescription)
|
||||||
|
{
|
||||||
|
var outputVariable = new VariableDefinition(_mObjectArrayType);
|
||||||
|
ilProcessor.Body.Variables.Add(outputVariable);
|
||||||
|
_currentOutputVariables.Add(outputDescription.Name, outputVariable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitBlockStatement(function.Body, methodDefinition);
|
||||||
|
|
||||||
|
// Copy output variables to the output array.
|
||||||
|
if (function.OutputDescription.Length > 0)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldc_I4, function.OutputDescription.Length);
|
||||||
|
ilProcessor.Emit(OpCodes.Newarr, _mObjectType);
|
||||||
|
for (var i = 0; i < function.OutputDescription.Length; i++)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Dup);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldc_I4, i);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc, i + 1);
|
||||||
|
ilProcessor.Emit(OpCodes.Stelem_Ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ilProcessor.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
|
foreach (var (index, target) in _forwardLabelsToFix)
|
||||||
|
{
|
||||||
|
var targetIndex = _labels[target];
|
||||||
|
var left = ilProcessor.Body.Instructions[index];
|
||||||
|
var right = ilProcessor.Body.Instructions[targetIndex];
|
||||||
|
left.Operand = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitBlockStatement(BoundBlockStatement block, MethodDefinition methodDefinition)
|
||||||
|
{
|
||||||
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
foreach (var statement in block.Statements)
|
||||||
|
{
|
||||||
|
switch (statement.Kind)
|
||||||
|
{
|
||||||
|
case BoundNodeKind.GotoStatement:
|
||||||
|
EmitGoto((BoundGotoStatement)statement, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.ConditionalGotoStatement:
|
||||||
|
EmitConditionalGoto((BoundConditionalGotoStatement)statement, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.LabelStatement:
|
||||||
|
EmitLabelStatement((BoundLabelStatement)statement, ilProcessor);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
EmitStatement(statement, ilProcessor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitLabelStatement(BoundLabelStatement node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
_labels[node.Label] = ilProcessor.Body.Instructions.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitGoto(BoundGotoStatement node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
if (_labels.TryGetValue(node.Label, out var target))
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Br, ilProcessor.Body.Instructions[target]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_forwardLabelsToFix.Add(ilProcessor.Body.Instructions.Count, node.Label);
|
||||||
|
ilProcessor.Emit(OpCodes.Br, Instruction.Create(OpCodes.Nop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitConditionalGoto(BoundConditionalGotoStatement node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
var condition = TryConvertExpression(node.Condition, TypeSymbol.Boolean);
|
||||||
|
if (condition is null)
|
||||||
|
{
|
||||||
|
throw new Exception("Cannot cast a condition in GOTO to boolean.");
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitExpression(condition, ilProcessor);
|
||||||
|
var instruction = node.GotoIfTrue ? OpCodes.Brtrue : OpCodes.Brfalse;
|
||||||
|
if (_labels.TryGetValue(node.Label, out var target))
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(instruction, ilProcessor.Body.Instructions[target]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_forwardLabelsToFix.Add(ilProcessor.Body.Instructions.Count, node.Label);
|
||||||
|
ilProcessor.Emit(instruction, Instruction.Create(OpCodes.Nop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitStatement(BoundStatement node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
switch (node.Kind)
|
||||||
|
{
|
||||||
|
case BoundNodeKind.EmptyStatement:
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.ExpressionStatement:
|
||||||
|
EmitExpressionStatement((BoundExpressionStatement)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.TypedVariableDeclaration:
|
||||||
|
EmitTypedVariableDeclaration((BoundTypedVariableDeclaration)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Invalid statement kind '{node.Kind}'.");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitTypedVariableDeclaration(BoundTypedVariableDeclaration node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
var typeReference = _resolvedTypes[node.Variable.Type];
|
||||||
|
var variableDefinition = new VariableDefinition(typeReference);
|
||||||
|
_typedLocals.Add(node.Variable, variableDefinition);
|
||||||
|
ilProcessor.Body.Variables.Add(variableDefinition);
|
||||||
|
|
||||||
|
EmitExpression(node.Initializer, ilProcessor);
|
||||||
|
ilProcessor.Emit(OpCodes.Stloc, variableDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitExpressionStatement(BoundExpressionStatement node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
EmitExpression(node.Expression, ilProcessor);
|
||||||
|
if (node.DiscardResult)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Pop);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _dispReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitExpression(BoundExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
switch (node.Kind) {
|
||||||
|
case BoundNodeKind.AssignmentExpression:
|
||||||
|
EmitAssignmentExpression((BoundAssignmentExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.BinaryOperationExpression:
|
||||||
|
EmitBinaryOperationExpression((BoundBinaryOperationExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.ConversionExpression:
|
||||||
|
EmitConversionExpression((BoundConversionExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.FunctionCallExpression:
|
||||||
|
EmitFunctionCallExpression((BoundFunctionCallExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.IdentifierNameExpression:
|
||||||
|
EmitIdentifierNameExpression((BoundIdentifierNameExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.NumberDoubleLiteralExpression:
|
||||||
|
EmitNumberDoubleLiteralExpression((BoundNumberDoubleLiteralExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.NumberIntLiteralExpression:
|
||||||
|
EmitNumberIntLiteralExpression((BoundNumberIntLiteralExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.StringLiteralExpression:
|
||||||
|
EmitStringLiteralExpression((BoundStringLiteralExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.TypedFunctionCallExpression:
|
||||||
|
EmitTypedFunctionCallExpression((BoundTypedFunctionCallExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.TypedVariableExpression:
|
||||||
|
EmitTypedVariableExpression((BoundTypedVariableExpression)node, ilProcessor);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"Invalid node kind '{node.Kind}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitConversionExpression(BoundConversionExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
var fromType = node.Expression.Type;
|
||||||
|
var toType = node.TargetType;
|
||||||
|
EmitExpression(node.Expression, ilProcessor);
|
||||||
|
if ((fromType, toType) == (TypeSymbol.Double, TypeSymbol.MObject))
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _doubleToMObject);
|
||||||
|
}
|
||||||
|
else if ((fromType, toType) == (TypeSymbol.Int, TypeSymbol.MObject))
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _intToMObject);
|
||||||
|
}
|
||||||
|
else if ((fromType, toType) == (TypeSymbol.String, TypeSymbol.MObject))
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _stringToMObject);
|
||||||
|
}
|
||||||
|
else if ((fromType, toType) == (TypeSymbol.MObject, TypeSymbol.Boolean))
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _mObjectToBool);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Conversion of '{fromType}' to '{toType}' is not implemented.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitTypedVariableExpression(BoundTypedVariableExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
var variableDefinition = _typedLocals[node.Variable];
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc, variableDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitBinaryOperationExpression(BoundBinaryOperationExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
if (_binaryOperations.TryGetValue(node.Op.Kind, out var method))
|
||||||
|
{
|
||||||
|
EmitExpression(node.Left, ilProcessor);
|
||||||
|
EmitExpression(node.Right, ilProcessor);
|
||||||
|
ilProcessor.Emit(OpCodes.Call, method);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if (node.Op.Kind == BoundBinaryOperatorKind.LessInt)
|
||||||
|
{
|
||||||
|
EmitExpression(node.Left, ilProcessor);
|
||||||
|
EmitExpression(node.Right, ilProcessor);
|
||||||
|
ilProcessor.Emit(OpCodes.Clt);
|
||||||
|
}
|
||||||
|
else if (node.Op.Kind == BoundBinaryOperatorKind.PlusInt)
|
||||||
|
{
|
||||||
|
EmitExpression(node.Left, ilProcessor);
|
||||||
|
EmitExpression(node.Right, ilProcessor);
|
||||||
|
ilProcessor.Emit(OpCodes.Add);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"Binary operation '{node.Op.Kind}' not implemented.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitAssignmentExpression(BoundAssignmentExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
var leftType = node.Left.Kind switch
|
||||||
|
{
|
||||||
|
BoundNodeKind.IdentifierNameExpression => TypeSymbol.MObject,
|
||||||
|
BoundNodeKind.TypedVariableExpression => ((BoundTypedVariableExpression)node.Left).Type,
|
||||||
|
_ => throw new Exception($"Assignment to lvalue of kind {node.Left.Kind} is not supported."),
|
||||||
|
};
|
||||||
|
|
||||||
|
var rewrittenRight = TryConvertExpression(node.Right, leftType);
|
||||||
|
if (rewrittenRight is null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Cannot convert an expression of type '{node.Right.Type}' to '{leftType}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.Left.Kind == BoundNodeKind.IdentifierNameExpression)
|
||||||
|
{
|
||||||
|
var left = ((BoundIdentifierNameExpression)node.Left);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldstr, left.Name);
|
||||||
|
EmitExpression(rewrittenRight, ilProcessor);
|
||||||
|
ilProcessor.Emit(OpCodes.Callvirt, _putItemIntoDictionary);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldstr, left.Name);
|
||||||
|
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
|
||||||
|
}
|
||||||
|
else if (node.Left.Kind == BoundNodeKind.TypedVariableExpression)
|
||||||
|
{
|
||||||
|
var typedVariableExpression = (BoundTypedVariableExpression)node.Left;
|
||||||
|
EmitExpression(rewrittenRight, ilProcessor);
|
||||||
|
ilProcessor.Emit(OpCodes.Dup);
|
||||||
|
ilProcessor.Emit(OpCodes.Stloc, _typedLocals[typedVariableExpression.Variable]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"Assignment to lvalue of kind {node.Left.Kind} is not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitIdentifierNameExpression(BoundIdentifierNameExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldstr, node.Name);
|
||||||
|
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitNumberDoubleLiteralExpression(BoundNumberDoubleLiteralExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldc_R8, node.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitNumberIntLiteralExpression(BoundNumberIntLiteralExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldc_I4, node.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitStringLiteralExpression(BoundStringLiteralExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldstr, node.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoundExpression? TryConvertExpression(BoundExpression expression, TypeSymbol targetType)
|
||||||
|
{
|
||||||
|
var conversion = Conversion.Classify(expression.Type, targetType);
|
||||||
|
if (!conversion.Exists)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conversion.IsIdentity)
|
||||||
|
{
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BoundNodeFactory.Conversion(expression.Syntax, targetType, expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoundExpression ConvertExpression(BoundExpression expression, TypeSymbol targetType)
|
||||||
|
{
|
||||||
|
return TryConvertExpression(expression, targetType)
|
||||||
|
?? throw new Exception($"Conversion from '{expression.Type}' to '{targetType}' failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoundExpression RewriteFunctionCall(BoundFunctionCallExpression node, TypedFunctionSymbol function)
|
||||||
|
{
|
||||||
|
var numberOfArguments = node.Arguments.Length;
|
||||||
|
if (numberOfArguments != function.Parameters.Length)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Function '{function.Name}' expected {function.Parameters.Length} arguments, but was called with {numberOfArguments}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var rewrittenArguments = ImmutableArray.CreateBuilder<BoundExpression>(numberOfArguments);
|
||||||
|
for (var i = 0; i < numberOfArguments; i++)
|
||||||
|
{
|
||||||
|
var argument = node.Arguments[i];
|
||||||
|
var parameter = function.Parameters[i];
|
||||||
|
var rewrittenArgument = TryConvertExpression(argument, parameter.Type);
|
||||||
|
if (rewrittenArgument is null)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Argument number {i + 1} of function '{function.Name}' expects {parameter.Type}, but got {argument.Type}, and no conversion exists.");
|
||||||
|
|
||||||
|
}
|
||||||
|
rewrittenArguments.Add(rewrittenArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BoundNodeFactory.TypedFunctionCall(node.Syntax, function, rewrittenArguments.MoveToImmutable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitTypedFunctionCallExpression(BoundTypedFunctionCallExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
var function = _builtInFunctions[node.Function];
|
||||||
|
foreach (var argument in node.Arguments)
|
||||||
|
{
|
||||||
|
EmitExpression(argument, ilProcessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ilProcessor.Emit(OpCodes.Call, function);
|
||||||
|
if (node.Function.ReturnType == TypeSymbol.Void)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldnull);
|
||||||
|
}
|
||||||
|
else if (node.Function.ReturnType == TypeSymbol.MObject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Don't know how to cast function output.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitFunctionCallExpression(BoundFunctionCallExpression node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
if (node.Name.Kind == BoundNodeKind.IdentifierNameExpression
|
||||||
|
&& ((BoundIdentifierNameExpression)node.Name).Name == "disp")
|
||||||
|
{
|
||||||
|
var dispFunctionSymbol = BuiltInFunctions.Disp;
|
||||||
|
var rewrittenCall = RewriteFunctionCall(node, dispFunctionSymbol);
|
||||||
|
EmitExpression(rewrittenCall, ilProcessor);
|
||||||
|
//ilProcessor.Emit(OpCodes.Call, _dispReference);
|
||||||
|
//ilProcessor.Emit(OpCodes.Ldnull);
|
||||||
|
} else if (node.Name.Kind == BoundNodeKind.IdentifierNameExpression
|
||||||
|
&& ((BoundIdentifierNameExpression)node.Name).Name == "len")
|
||||||
|
{
|
||||||
|
EmitExpression(node.Arguments[0], ilProcessor);
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _lenReference);
|
||||||
|
}
|
||||||
|
else if (node.Name.Kind == BoundNodeKind.TypedVariableExpression)
|
||||||
|
{
|
||||||
|
if (node.Arguments.Length > 1)
|
||||||
|
{
|
||||||
|
throw new Exception("Multi-dimensional array slicing is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var typedVariableExpression = ConvertExpression((BoundTypedVariableExpression)node.Name, TypeSymbol.MObject);
|
||||||
|
EmitExpression(typedVariableExpression, ilProcessor);
|
||||||
|
var indexExpression = ConvertExpression(node.Arguments[0], TypeSymbol.MObject);
|
||||||
|
EmitExpression(indexExpression, ilProcessor);
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _arraySliceReference);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var function = ResolveFunction(node.Name);
|
||||||
|
for (var i = 0; i < function.InputDescription.Length; i++)
|
||||||
|
{
|
||||||
|
if (i < node.Arguments.Length)
|
||||||
|
{
|
||||||
|
EmitExpression(node.Arguments[i], ilProcessor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldnull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ilProcessor.Emit(OpCodes.Call, function.Method);
|
||||||
|
if (function.OutputDescription.Length == 0)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldnull);
|
||||||
|
}
|
||||||
|
else if (function.OutputDescription.Length == 1)
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Ldc_I4_0);
|
||||||
|
ilProcessor.Emit(OpCodes.Ldelem_Ref);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Functions with multiple output are not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodInterfaceDescription ResolveFunction(BoundExpression node)
|
||||||
|
{
|
||||||
|
if (node.Kind == BoundNodeKind.IdentifierNameExpression)
|
||||||
|
{
|
||||||
|
var name = ((BoundIdentifierNameExpression)node).Name;
|
||||||
|
if (_functions.TryGetValue(name, out var result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw new Exception($"Function '{name}' not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Dynamic functions calling not supported. Failed to resolve function call expression with kind '{node.Kind}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
Parser/Emitting/MethodInterfaceDescription.cs
Normal file
22
Parser/Emitting/MethodInterfaceDescription.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Mono.Cecil;
|
||||||
|
using Parser.Binding;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Parser.Emitting
|
||||||
|
{
|
||||||
|
public class MethodInterfaceDescription
|
||||||
|
{
|
||||||
|
public MethodInterfaceDescription(ImmutableArray<ParameterSymbol> inputDescription, ImmutableArray<ParameterSymbol> outputDescription, MethodDefinition method)
|
||||||
|
{
|
||||||
|
InputDescription = inputDescription;
|
||||||
|
OutputDescription = outputDescription;
|
||||||
|
Method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableArray<ParameterSymbol> InputDescription { get; }
|
||||||
|
|
||||||
|
public ImmutableArray<ParameterSymbol> OutputDescription { get; }
|
||||||
|
|
||||||
|
public MethodDefinition Method { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -39,7 +39,7 @@ namespace Parser
|
|||||||
if (mainFunction.InputDescription.Length > 0)
|
if (mainFunction.InputDescription.Length > 0)
|
||||||
{
|
{
|
||||||
_diagnostics.ReportNotEnoughInputs(
|
_diagnostics.ReportNotEnoughInputs(
|
||||||
new TextSpan(mainFunction.Body.Syntax.Position, mainFunction.Body.Syntax.Position + mainFunction.Body.Syntax.FullWidth),
|
mainFunction.Body.Syntax.Span,
|
||||||
mainFunction.Name);
|
mainFunction.Name);
|
||||||
return new EvaluationResult(null, _diagnostics.ToImmutableArray());
|
return new EvaluationResult(null, _diagnostics.ToImmutableArray());
|
||||||
}
|
}
|
||||||
@ -210,7 +210,8 @@ namespace Parser
|
|||||||
|
|
||||||
private MObject? EvaluateExpressionStatement(BoundExpressionStatement node)
|
private MObject? EvaluateExpressionStatement(BoundExpressionStatement node)
|
||||||
{
|
{
|
||||||
return EvaluateExpression(node.Expression);
|
var result = EvaluateExpression(node.Expression);
|
||||||
|
return node.DiscardResult ? null : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateExpression(BoundExpression node)
|
private MObject? EvaluateExpression(BoundExpression node)
|
||||||
@ -249,8 +250,10 @@ namespace Parser
|
|||||||
EvaluateMemberAccess((BoundMemberAccessExpression)node),
|
EvaluateMemberAccess((BoundMemberAccessExpression)node),
|
||||||
BoundNodeKind.NamedFunctionHandleExpression =>
|
BoundNodeKind.NamedFunctionHandleExpression =>
|
||||||
EvaluateNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
EvaluateNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
||||||
BoundNodeKind.NumberLiteralExpression =>
|
BoundNodeKind.NumberDoubleLiteralExpression =>
|
||||||
EvaluateNumberLiteralExpression((BoundNumberLiteralExpression)node),
|
EvaluateNumberDoubleLiteralExpression((BoundNumberDoubleLiteralExpression)node),
|
||||||
|
BoundNodeKind.NumberIntLiteralExpression =>
|
||||||
|
EvaluateNumberIntLiteralExpression((BoundNumberIntLiteralExpression)node),
|
||||||
BoundNodeKind.StringLiteralExpression =>
|
BoundNodeKind.StringLiteralExpression =>
|
||||||
EvaluateStringLiteralExpression((BoundStringLiteralExpression)node),
|
EvaluateStringLiteralExpression((BoundStringLiteralExpression)node),
|
||||||
BoundNodeKind.UnaryOperationExpression =>
|
BoundNodeKind.UnaryOperationExpression =>
|
||||||
@ -288,10 +291,9 @@ namespace Parser
|
|||||||
foreach (var argument in node.Arguments)
|
foreach (var argument in node.Arguments)
|
||||||
{
|
{
|
||||||
var evaluatedArgument = EvaluateExpression(argument);
|
var evaluatedArgument = EvaluateExpression(argument);
|
||||||
if (argument is null)
|
if (evaluatedArgument is null)
|
||||||
{
|
{
|
||||||
_diagnostics.ReportCannotEvaluateExpression(
|
_diagnostics.ReportCannotEvaluateExpression(argument.Syntax.Span);
|
||||||
new TextSpan(argument.Syntax.Position, argument.Syntax.FullWidth));
|
|
||||||
allGood = false;
|
allGood = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -316,9 +318,7 @@ namespace Parser
|
|||||||
if (resolvedFunction is null)
|
if (resolvedFunction is null)
|
||||||
{
|
{
|
||||||
_diagnostics.ReportFunctionNotFound(
|
_diagnostics.ReportFunctionNotFound(
|
||||||
new TextSpan(
|
node.Name.Syntax.Span,
|
||||||
node.Name.Syntax.Position,
|
|
||||||
node.Name.Syntax.Position + node.Name.Syntax.FullWidth),
|
|
||||||
function.Name);
|
function.Name);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -340,10 +340,8 @@ namespace Parser
|
|||||||
if (counter < arguments.Count)
|
if (counter < arguments.Count)
|
||||||
{
|
{
|
||||||
_diagnostics.ReportTooManyInputs(
|
_diagnostics.ReportTooManyInputs(
|
||||||
new TextSpan(
|
node.Arguments[counter].Syntax.Span,
|
||||||
node.Arguments[counter].Syntax.Position,
|
function.Name);
|
||||||
node.Arguments[counter].Syntax.Position + node.Arguments[counter].Syntax.FullWidth),
|
|
||||||
function.Name);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
_scopeStack.Push(newScope);
|
_scopeStack.Push(newScope);
|
||||||
@ -419,7 +417,12 @@ namespace Parser
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateNumberLiteralExpression(BoundNumberLiteralExpression node)
|
private MObject? EvaluateNumberDoubleLiteralExpression(BoundNumberDoubleLiteralExpression node)
|
||||||
|
{
|
||||||
|
return MObject.CreateDoubleNumber(node.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MObject? EvaluateNumberIntLiteralExpression(BoundNumberIntLiteralExpression node)
|
||||||
{
|
{
|
||||||
return MObject.CreateDoubleNumber(node.Value);
|
return MObject.CreateDoubleNumber(node.Value);
|
||||||
}
|
}
|
||||||
@ -431,7 +434,7 @@ namespace Parser
|
|||||||
if (maybeValue is null)
|
if (maybeValue is null)
|
||||||
{
|
{
|
||||||
_diagnostics.ReportVariableNotFound(
|
_diagnostics.ReportVariableNotFound(
|
||||||
new TextSpan(node.Syntax.Position, node.Syntax.FullWidth),
|
node.Syntax.Span,
|
||||||
variableName);
|
variableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,7 +500,7 @@ namespace Parser
|
|||||||
if (rightValue is null)
|
if (rightValue is null)
|
||||||
{
|
{
|
||||||
_diagnostics.ReportCannotEvaluateExpression(
|
_diagnostics.ReportCannotEvaluateExpression(
|
||||||
new TextSpan(node.Right.Syntax.Position, node.Right.Syntax.Position + node.Right.Syntax.FullWidth));
|
node.Right.Syntax.Span);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,11 @@ namespace Parser.Internal
|
|||||||
Report(span, $"Unexpected character '{c}' while parsing a number.");
|
Report(span, $"Unexpected character '{c}' while parsing a number.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void ReportMainIsNotAllowed(TextSpan span)
|
||||||
|
{
|
||||||
|
Report(span, $"Function name 'Main' is not allowed in scripts.");
|
||||||
|
}
|
||||||
|
|
||||||
internal void ReportUnexpectedEOLWhileParsingString(TextSpan span)
|
internal void ReportUnexpectedEOLWhileParsingString(TextSpan span)
|
||||||
{
|
{
|
||||||
Report(span, "Unexpected end of line while parsing a string literal.");
|
Report(span, "Unexpected end of line while parsing a string literal.");
|
||||||
@ -102,5 +107,10 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
Report(span, $"Too many inputs in the call to '{functionName}'.");
|
Report(span, $"Too many inputs in the call to '{functionName}'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void ReportForLoopWithoutVariable(TextSpan span)
|
||||||
|
{
|
||||||
|
Report(span, $"A 'for' loop must have a loop variable.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -191,11 +191,11 @@ namespace Parser.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual IReadOnlyList<SyntaxTrivia> LeadingTrivia => GetFirstTerminal()?.LeadingTriviaCore ?? new List<SyntaxTrivia>();
|
public virtual GreenNode? LeadingTrivia => GetFirstTerminal()?.LeadingTriviaCore;
|
||||||
public virtual IReadOnlyList<SyntaxTrivia> TrailingTrivia => GetLastTerminal()?.TrailingTriviaCore ?? new List<SyntaxTrivia>();
|
public virtual GreenNode? TrailingTrivia => GetLastTerminal()?.TrailingTriviaCore;
|
||||||
|
|
||||||
public abstract IReadOnlyList<SyntaxTrivia> LeadingTriviaCore { get; }
|
public virtual GreenNode? LeadingTriviaCore => null;
|
||||||
public abstract IReadOnlyList<SyntaxTrivia> TrailingTriviaCore { get; }
|
public virtual GreenNode? TrailingTriviaCore => null;
|
||||||
|
|
||||||
public virtual string FullText
|
public virtual string FullText
|
||||||
{
|
{
|
||||||
@ -209,7 +209,6 @@ namespace Parser.Internal
|
|||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,7 +493,7 @@ namespace Parser.Internal
|
|||||||
if (TokensSinceNewLine == 1
|
if (TokensSinceNewLine == 1
|
||||||
&& !TokenStack.Any()
|
&& !TokenStack.Any()
|
||||||
&& LastToken.Kind == TokenKind.IdentifierToken
|
&& LastToken.Kind == TokenKind.IdentifierToken
|
||||||
&& LastToken.TrailingTrivia.Any()
|
&& LastToken.TrailingTrivia is not null
|
||||||
&& character != '='
|
&& character != '='
|
||||||
&& character != '('
|
&& character != '('
|
||||||
&& !SyntaxFacts.Keywords.Contains(LastToken.Text))
|
&& !SyntaxFacts.Keywords.Contains(LastToken.Text))
|
||||||
@ -773,7 +773,7 @@ namespace Parser.Internal
|
|||||||
|| LastToken.Kind == TokenKind.CloseSquareBracketToken
|
|| LastToken.Kind == TokenKind.CloseSquareBracketToken
|
||||||
|| LastToken.Kind == TokenKind.IdentifierToken))
|
|| LastToken.Kind == TokenKind.IdentifierToken))
|
||||||
{
|
{
|
||||||
if (LastToken.TrailingTrivia.Count == 0 && leadingTrivia.Count == 0)
|
if (LastToken.TrailingTrivia is null && leadingTrivia.Count == 0)
|
||||||
{
|
{
|
||||||
Window.ConsumeChar();
|
Window.ConsumeChar();
|
||||||
tokenInfo.Kind = TokenKind.ApostropheToken;
|
tokenInfo.Kind = TokenKind.ApostropheToken;
|
||||||
@ -858,46 +858,40 @@ namespace Parser.Internal
|
|||||||
List<SyntaxTrivia> leadingTrivia,
|
List<SyntaxTrivia> leadingTrivia,
|
||||||
List<SyntaxTrivia> trailingTrivia)
|
List<SyntaxTrivia> trailingTrivia)
|
||||||
{
|
{
|
||||||
switch (tokenInfo.Kind)
|
return tokenInfo.Kind switch
|
||||||
{
|
{
|
||||||
case TokenKind.IdentifierToken:
|
TokenKind.IdentifierToken => TokenFactory.CreateIdentifier(
|
||||||
return TokenFactory.CreateIdentifier(
|
tokenInfo.Text,
|
||||||
tokenInfo.Text,
|
leadingTrivia,
|
||||||
leadingTrivia,
|
trailingTrivia),
|
||||||
trailingTrivia);
|
TokenKind.UnquotedStringLiteralToken => TokenFactory.CreateUnquotedStringLiteral(
|
||||||
case TokenKind.UnquotedStringLiteralToken:
|
tokenInfo.Text,
|
||||||
return TokenFactory.CreateUnquotedStringLiteral(
|
tokenInfo.StringValue,
|
||||||
tokenInfo.Text,
|
leadingTrivia,
|
||||||
tokenInfo.StringValue,
|
trailingTrivia),
|
||||||
leadingTrivia,
|
TokenKind.NumberLiteralToken => TokenFactory.CreateTokenWithValueAndTrivia<double>(
|
||||||
trailingTrivia);
|
tokenInfo.Kind,
|
||||||
case TokenKind.NumberLiteralToken:
|
tokenInfo.Text,
|
||||||
return TokenFactory.CreateTokenWithValueAndTrivia<double>(
|
tokenInfo.DoubleValue,
|
||||||
tokenInfo.Kind,
|
leadingTrivia,
|
||||||
tokenInfo.Text,
|
trailingTrivia),
|
||||||
tokenInfo.DoubleValue,
|
TokenKind.StringLiteralToken => TokenFactory.CreateTokenWithValueAndTrivia<string>(
|
||||||
leadingTrivia,
|
tokenInfo.Kind,
|
||||||
trailingTrivia);
|
tokenInfo.Text,
|
||||||
case TokenKind.StringLiteralToken:
|
tokenInfo.StringValue,
|
||||||
return TokenFactory.CreateTokenWithValueAndTrivia<string>(
|
leadingTrivia,
|
||||||
tokenInfo.Kind,
|
trailingTrivia),
|
||||||
tokenInfo.Text,
|
TokenKind.DoubleQuotedStringLiteralToken => TokenFactory.CreateTokenWithValueAndTrivia<string>(
|
||||||
tokenInfo.StringValue,
|
tokenInfo.Kind,
|
||||||
leadingTrivia,
|
tokenInfo.Text,
|
||||||
trailingTrivia);
|
tokenInfo.StringValue,
|
||||||
case TokenKind.DoubleQuotedStringLiteralToken:
|
leadingTrivia,
|
||||||
return TokenFactory.CreateTokenWithValueAndTrivia<string>(
|
trailingTrivia),
|
||||||
tokenInfo.Kind,
|
_ => TokenFactory.CreateTokenWithTrivia(
|
||||||
tokenInfo.Text,
|
tokenInfo.Kind,
|
||||||
tokenInfo.StringValue,
|
leadingTrivia,
|
||||||
leadingTrivia,
|
trailingTrivia),
|
||||||
trailingTrivia);
|
};
|
||||||
default:
|
|
||||||
return TokenFactory.CreateTokenWithTrivia(
|
|
||||||
tokenInfo.Kind,
|
|
||||||
leadingTrivia,
|
|
||||||
trailingTrivia);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<(SyntaxToken, Position)> ParseAll()
|
public List<(SyntaxToken, Position)> ParseAll()
|
||||||
|
@ -76,17 +76,6 @@ namespace Parser.Internal
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SyntaxToken? PossiblyEatIdentifier(string s)
|
|
||||||
{
|
|
||||||
var token = CurrentToken;
|
|
||||||
if (token.Kind == TokenKind.IdentifierToken && token.Text == s)
|
|
||||||
{
|
|
||||||
return EatToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SyntaxToken EatPossiblyMissingIdentifier(string s)
|
private SyntaxToken EatPossiblyMissingIdentifier(string s)
|
||||||
{
|
{
|
||||||
var token = CurrentToken;
|
var token = CurrentToken;
|
||||||
@ -181,6 +170,10 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
var identifierToken = EatToken(TokenKind.IdentifierToken);
|
var identifierToken = EatToken(TokenKind.IdentifierToken);
|
||||||
builder.Add(Factory.IdentifierNameExpressionSyntax(identifierToken));
|
builder.Add(Factory.IdentifierNameExpressionSyntax(identifierToken));
|
||||||
|
if (identifierToken.IsMissing)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,43 +293,20 @@ namespace Parser.Internal
|
|||||||
return builder.ToList();
|
return builder.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionSyntaxNode? ParseTerm(ParseOptions options)
|
private ExpressionSyntaxNode ParseTerm(ParseOptions options)
|
||||||
{
|
{
|
||||||
var token = CurrentToken;
|
var token = CurrentToken;
|
||||||
ExpressionSyntaxNode? expression = null;
|
ExpressionSyntaxNode expression = token.Kind switch
|
||||||
switch (token.Kind)
|
|
||||||
{
|
{
|
||||||
case TokenKind.NumberLiteralToken:
|
TokenKind.NumberLiteralToken => Factory.NumberLiteralExpressionSyntax(EatToken()),
|
||||||
expression = Factory.NumberLiteralExpressionSyntax(EatToken());
|
TokenKind.StringLiteralToken => Factory.StringLiteralExpressionSyntax(EatToken()),
|
||||||
break;
|
TokenKind.DoubleQuotedStringLiteralToken => Factory.DoubleQuotedStringLiteralExpressionSyntax(EatToken()),
|
||||||
case TokenKind.StringLiteralToken:
|
TokenKind.OpenSquareBracketToken => ParseArrayLiteral(),
|
||||||
expression = Factory.StringLiteralExpressionSyntax(EatToken());
|
TokenKind.OpenBraceToken => ParseCellArrayLiteral(),
|
||||||
break;
|
TokenKind.ColonToken => Factory.EmptyExpressionSyntax(),
|
||||||
case TokenKind.DoubleQuotedStringLiteralToken:
|
TokenKind.OpenParenthesisToken => ParseParenthesizedExpression(),
|
||||||
expression = Factory.DoubleQuotedStringLiteralExpressionSyntax(EatToken());
|
_ => Factory.IdentifierNameExpressionSyntax(EatToken(TokenKind.IdentifierToken)),
|
||||||
break;
|
};
|
||||||
case TokenKind.OpenSquareBracketToken:
|
|
||||||
expression = ParseArrayLiteral();
|
|
||||||
break;
|
|
||||||
case TokenKind.OpenBraceToken:
|
|
||||||
expression = ParseCellArrayLiteral();
|
|
||||||
break;
|
|
||||||
case TokenKind.ColonToken:
|
|
||||||
expression = Factory.EmptyExpressionSyntax();
|
|
||||||
break;
|
|
||||||
case TokenKind.OpenParenthesisToken:
|
|
||||||
expression = ParseParenthesizedExpression();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
var id = EatToken(TokenKind.IdentifierToken);
|
|
||||||
expression = Factory.IdentifierNameExpressionSyntax(id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expression == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return ParsePostfix(options, expression);
|
return ParsePostfix(options, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +318,7 @@ namespace Parser.Internal
|
|||||||
switch (token.Kind)
|
switch (token.Kind)
|
||||||
{
|
{
|
||||||
case TokenKind.OpenBraceToken: // cell array element access
|
case TokenKind.OpenBraceToken: // cell array element access
|
||||||
if (options.ParsingArrayElements && expression.TrailingTrivia.Any())
|
if (options.ParsingArrayElements && expression.TrailingTrivia is not null)
|
||||||
{
|
{
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
@ -363,7 +333,7 @@ namespace Parser.Internal
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case TokenKind.OpenParenthesisToken: // function call
|
case TokenKind.OpenParenthesisToken: // function call
|
||||||
if (options.ParsingArrayElements && expression.TrailingTrivia.Any())
|
if (options.ParsingArrayElements && expression.TrailingTrivia is not null)
|
||||||
{
|
{
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
@ -401,7 +371,7 @@ namespace Parser.Internal
|
|||||||
case TokenKind.UnquotedStringLiteralToken:
|
case TokenKind.UnquotedStringLiteralToken:
|
||||||
return ParseCommandExpression(expression);
|
return ParseCommandExpression(expression);
|
||||||
case TokenKind.AtToken:
|
case TokenKind.AtToken:
|
||||||
if (expression.TrailingTrivia.Any())
|
if (expression.TrailingTrivia is not null)
|
||||||
{
|
{
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
@ -435,7 +405,7 @@ namespace Parser.Internal
|
|||||||
private ClassInvokationExpressionSyntaxNode ParseBaseClassInvokation(ExpressionSyntaxNode expression)
|
private ClassInvokationExpressionSyntaxNode ParseBaseClassInvokation(ExpressionSyntaxNode expression)
|
||||||
{
|
{
|
||||||
if (expression is IdentifierNameExpressionSyntaxNode methodName
|
if (expression is IdentifierNameExpressionSyntaxNode methodName
|
||||||
&& !expression.TrailingTrivia.Any())
|
&& expression.TrailingTrivia is null)
|
||||||
{
|
{
|
||||||
var atToken = EatToken();
|
var atToken = EatToken();
|
||||||
var baseClassNameWithArguments = ParseExpression();
|
var baseClassNameWithArguments = ParseExpression();
|
||||||
@ -446,7 +416,7 @@ namespace Parser.Internal
|
|||||||
return Factory.ClassInvokationExpressionSyntax(methodName, atToken, baseClassNameWithArguments);
|
return Factory.ClassInvokationExpressionSyntax(methodName, atToken, baseClassNameWithArguments);
|
||||||
}
|
}
|
||||||
if (expression is MemberAccessExpressionSyntaxNode memberAccess
|
if (expression is MemberAccessExpressionSyntaxNode memberAccess
|
||||||
&& !expression.TrailingTrivia.Any())
|
&& expression.TrailingTrivia is null)
|
||||||
{
|
{
|
||||||
var atToken = EatToken();
|
var atToken = EatToken();
|
||||||
var baseClassNameWithArguments = ParseExpression();
|
var baseClassNameWithArguments = ParseExpression();
|
||||||
@ -530,7 +500,7 @@ namespace Parser.Internal
|
|||||||
var builder = new SyntaxListBuilder();
|
var builder = new SyntaxListBuilder();
|
||||||
builder.Add(firstName);
|
builder.Add(firstName);
|
||||||
while (CurrentToken.Kind == TokenKind.DotToken
|
while (CurrentToken.Kind == TokenKind.DotToken
|
||||||
&& !lastToken.TrailingTrivia.Any())
|
&& lastToken.TrailingTrivia is null)
|
||||||
{
|
{
|
||||||
var dot = EatToken();
|
var dot = EatToken();
|
||||||
builder.Add(dot);
|
builder.Add(dot);
|
||||||
@ -599,10 +569,6 @@ namespace Parser.Internal
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
lhs = ParseTerm(options);
|
lhs = ParseTerm(options);
|
||||||
if (lhs is null)
|
|
||||||
{
|
|
||||||
throw new Exception("Left-hand side in subexpression cannot be empty.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
@ -845,7 +811,34 @@ namespace Parser.Internal
|
|||||||
throw new Exception("Expression statement cannot be empty.");
|
throw new Exception("Expression statement cannot be empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Factory.ExpressionStatementSyntax(expression);
|
if (CurrentToken.Kind == TokenKind.SemicolonToken && !TriviaContainsNewLine(expression.TrailingTrivia))
|
||||||
|
{
|
||||||
|
var semicolon = EatToken();
|
||||||
|
return Factory.ExpressionStatementSyntax(
|
||||||
|
expression,
|
||||||
|
Factory.TrailingSemicolonSyntax(semicolon));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Factory.ExpressionStatementSyntax(expression, semicolon: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TriviaContainsNewLine(GreenNode? trivia)
|
||||||
|
{
|
||||||
|
if (trivia is not SyntaxList<SyntaxTrivia> triviaList)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < triviaList.Length; i++)
|
||||||
|
{
|
||||||
|
var text = triviaList[i].Text;
|
||||||
|
if (text.Contains('\n'))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AttributeAssignmentSyntaxNode? ParseAttributeAssignment()
|
private AttributeAssignmentSyntaxNode? ParseAttributeAssignment()
|
||||||
@ -1179,11 +1172,6 @@ namespace Parser.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentToken.Kind == TokenKind.OpenSquareBracketToken)
|
|
||||||
{
|
|
||||||
return ParseExpressionStatement();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentToken.Kind == TokenKind.SemicolonToken)
|
if (CurrentToken.Kind == TokenKind.SemicolonToken)
|
||||||
{
|
{
|
||||||
return Factory.EmptyStatementSyntax(EatToken());
|
return Factory.EmptyStatementSyntax(EatToken());
|
||||||
@ -1191,9 +1179,14 @@ namespace Parser.Internal
|
|||||||
return ParseExpressionStatement();
|
return ParseExpressionStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlockStatementSyntaxNode ParseBlockStatement()
|
private BlockStatementSyntaxNode? ParseBlockStatement()
|
||||||
{
|
{
|
||||||
var statements = ParseStatementList();
|
var statements = ParseStatementList();
|
||||||
|
if (statements.Length == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return Factory.BlockStatementSyntax(statements);
|
return Factory.BlockStatementSyntax(statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
internal partial class SyntaxFactory
|
internal partial class SyntaxFactory
|
||||||
{
|
{
|
||||||
public FileSyntaxNode FileSyntax(BlockStatementSyntaxNode body, SyntaxToken endOfFile)
|
public FileSyntaxNode FileSyntax(BlockStatementSyntaxNode? body, SyntaxToken endOfFile)
|
||||||
{
|
{
|
||||||
return new FileSyntaxNode(body, endOfFile);
|
return new FileSyntaxNode(body, endOfFile);
|
||||||
}
|
}
|
||||||
@ -78,9 +78,14 @@ namespace Parser.Internal
|
|||||||
return new TryCatchStatementSyntaxNode(tryKeyword, tryBody, catchClause, endKeyword);
|
return new TryCatchStatementSyntaxNode(tryKeyword, tryBody, catchClause, endKeyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpressionStatementSyntaxNode ExpressionStatementSyntax(ExpressionSyntaxNode expression)
|
public ExpressionStatementSyntaxNode ExpressionStatementSyntax(ExpressionSyntaxNode expression, TrailingSemicolonSyntaxNode? semicolon)
|
||||||
{
|
{
|
||||||
return new ExpressionStatementSyntaxNode(expression);
|
return new ExpressionStatementSyntaxNode(expression, semicolon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrailingSemicolonSyntaxNode TrailingSemicolonSyntax(SyntaxToken semicolon)
|
||||||
|
{
|
||||||
|
return new TrailingSemicolonSyntaxNode(semicolon);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmptyStatementSyntaxNode EmptyStatementSyntax(SyntaxToken semicolon)
|
public EmptyStatementSyntaxNode EmptyStatementSyntax(SyntaxToken semicolon)
|
||||||
|
@ -58,5 +58,7 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
return new SyntaxList(_elements, diagnostics);
|
return new SyntaxList(_elements, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Length => _elements.Length;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Parser.Internal
|
namespace Parser.Internal
|
||||||
{
|
{
|
||||||
@ -31,11 +32,18 @@ namespace Parser.Internal
|
|||||||
return (T)_list.GetListSlot(i);
|
return (T)_list.GetListSlot(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T this[int i] => (T)_list.GetListSlot(i);
|
||||||
|
|
||||||
public static SyntaxList<T> List(T[] elements)
|
public static SyntaxList<T> List(T[] elements)
|
||||||
{
|
{
|
||||||
return new SyntaxList<T>(elements);
|
return new SyntaxList<T>(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SyntaxList<T> List(IReadOnlyList<T> elements)
|
||||||
|
{
|
||||||
|
return new SyntaxList<T>(elements.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
public static SyntaxList<T> Empty => new SyntaxList<T>(new T[] { });
|
public static SyntaxList<T> Empty => new SyntaxList<T>(new T[] { });
|
||||||
|
|
||||||
public override bool IsList => true;
|
public override bool IsList => true;
|
||||||
@ -49,5 +57,7 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
return new SyntaxList<T>(_list._elements.Select(x => (T)x).ToArray(), diagnostics);
|
return new SyntaxList<T>(_list._elements.Select(x => (T)x).ToArray(), diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Length => _list.Length;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,9 +3,9 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
internal class FileSyntaxNode : SyntaxNode
|
internal class FileSyntaxNode : SyntaxNode
|
||||||
{
|
{
|
||||||
internal readonly BlockStatementSyntaxNode _body;
|
internal readonly BlockStatementSyntaxNode? _body;
|
||||||
internal readonly SyntaxToken _endOfFile;
|
internal readonly SyntaxToken _endOfFile;
|
||||||
internal FileSyntaxNode(BlockStatementSyntaxNode body, SyntaxToken endOfFile): base(TokenKind.File)
|
internal FileSyntaxNode(BlockStatementSyntaxNode? body, SyntaxToken endOfFile): base(TokenKind.File)
|
||||||
{
|
{
|
||||||
Slots = 2;
|
Slots = 2;
|
||||||
this.AdjustWidth(body);
|
this.AdjustWidth(body);
|
||||||
@ -14,7 +14,7 @@ namespace Parser.Internal
|
|||||||
_endOfFile = endOfFile;
|
_endOfFile = endOfFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal FileSyntaxNode(BlockStatementSyntaxNode body, SyntaxToken endOfFile, TokenDiagnostic[] diagnostics): base(TokenKind.File, diagnostics)
|
internal FileSyntaxNode(BlockStatementSyntaxNode? body, SyntaxToken endOfFile, TokenDiagnostic[] diagnostics): base(TokenKind.File, diagnostics)
|
||||||
{
|
{
|
||||||
Slots = 2;
|
Slots = 2;
|
||||||
this.AdjustWidth(body);
|
this.AdjustWidth(body);
|
||||||
@ -779,18 +779,23 @@ namespace Parser.Internal
|
|||||||
internal class ExpressionStatementSyntaxNode : StatementSyntaxNode
|
internal class ExpressionStatementSyntaxNode : StatementSyntaxNode
|
||||||
{
|
{
|
||||||
internal readonly ExpressionSyntaxNode _expression;
|
internal readonly ExpressionSyntaxNode _expression;
|
||||||
internal ExpressionStatementSyntaxNode(ExpressionSyntaxNode expression): base(TokenKind.ExpressionStatement)
|
internal readonly TrailingSemicolonSyntaxNode? _semicolon;
|
||||||
|
internal ExpressionStatementSyntaxNode(ExpressionSyntaxNode expression, TrailingSemicolonSyntaxNode? semicolon): base(TokenKind.ExpressionStatement)
|
||||||
{
|
{
|
||||||
Slots = 1;
|
Slots = 2;
|
||||||
this.AdjustWidth(expression);
|
this.AdjustWidth(expression);
|
||||||
_expression = expression;
|
_expression = expression;
|
||||||
|
this.AdjustWidth(semicolon);
|
||||||
|
_semicolon = semicolon;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ExpressionStatementSyntaxNode(ExpressionSyntaxNode expression, TokenDiagnostic[] diagnostics): base(TokenKind.ExpressionStatement, diagnostics)
|
internal ExpressionStatementSyntaxNode(ExpressionSyntaxNode expression, TrailingSemicolonSyntaxNode? semicolon, TokenDiagnostic[] diagnostics): base(TokenKind.ExpressionStatement, diagnostics)
|
||||||
{
|
{
|
||||||
Slots = 1;
|
Slots = 2;
|
||||||
this.AdjustWidth(expression);
|
this.AdjustWidth(expression);
|
||||||
_expression = expression;
|
_expression = expression;
|
||||||
|
this.AdjustWidth(semicolon);
|
||||||
|
_semicolon = semicolon;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position)
|
internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position)
|
||||||
@ -800,14 +805,52 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
{
|
{
|
||||||
return new ExpressionStatementSyntaxNode(_expression, diagnostics);
|
return new ExpressionStatementSyntaxNode(_expression, _semicolon, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override GreenNode? GetSlot(int i)
|
public override GreenNode? GetSlot(int i)
|
||||||
{
|
{
|
||||||
return i switch
|
return i switch
|
||||||
{
|
{
|
||||||
0 => _expression, _ => null
|
0 => _expression, 1 => _semicolon, _ => null
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class TrailingSemicolonSyntaxNode : SyntaxNode
|
||||||
|
{
|
||||||
|
internal readonly SyntaxToken _semicolon;
|
||||||
|
internal TrailingSemicolonSyntaxNode(SyntaxToken semicolon): base(TokenKind.TrailingSemicolon)
|
||||||
|
{
|
||||||
|
Slots = 1;
|
||||||
|
this.AdjustWidth(semicolon);
|
||||||
|
_semicolon = semicolon;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TrailingSemicolonSyntaxNode(SyntaxToken semicolon, TokenDiagnostic[] diagnostics): base(TokenKind.TrailingSemicolon, diagnostics)
|
||||||
|
{
|
||||||
|
Slots = 1;
|
||||||
|
this.AdjustWidth(semicolon);
|
||||||
|
_semicolon = semicolon;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override Parser.SyntaxNode CreateRed(Parser.SyntaxNode parent, int position)
|
||||||
|
{
|
||||||
|
return new Parser.TrailingSemicolonSyntaxNode(parent, this, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
{
|
||||||
|
return new TrailingSemicolonSyntaxNode(_semicolon, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override GreenNode? GetSlot(int i)
|
||||||
|
{
|
||||||
|
return i switch
|
||||||
|
{
|
||||||
|
0 => _semicolon, _ => null
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
;
|
||||||
|
@ -51,10 +51,10 @@ namespace Parser.Internal
|
|||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string FullText => CollectFullText();
|
//public override string FullText => CollectFullText();
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => throw new NotImplementedException();
|
public override GreenNode? LeadingTriviaCore => throw new NotImplementedException();
|
||||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => throw new NotImplementedException();
|
public override GreenNode? TrailingTriviaCore => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class StatementSyntaxNode : SyntaxNode
|
internal abstract class StatementSyntaxNode : SyntaxNode
|
||||||
@ -121,11 +121,11 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
public override GreenNode? GetSlot(int i)
|
public override GreenNode? GetSlot(int i)
|
||||||
{
|
{
|
||||||
switch (i)
|
return i switch
|
||||||
{
|
{
|
||||||
case 0: return _file;
|
0 => _file,
|
||||||
default: return null;
|
_ => null,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Parser.Internal
|
namespace Parser.Internal
|
||||||
{
|
{
|
||||||
@ -16,66 +15,66 @@ namespace Parser.Internal
|
|||||||
public SyntaxTokenWithTrivia(
|
public SyntaxTokenWithTrivia(
|
||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
string text,
|
string text,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia) : base(kind)
|
GreenNode? trailingTrivia) : base(kind)
|
||||||
{
|
{
|
||||||
_text = text;
|
_text = text;
|
||||||
LeadingTriviaCore = leadingTrivia;
|
LeadingTriviaCore = leadingTrivia;
|
||||||
TrailingTriviaCore = trailingTrivia;
|
TrailingTriviaCore = trailingTrivia;
|
||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.FullWidth ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.FullWidth ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SyntaxTokenWithTrivia(
|
public SyntaxTokenWithTrivia(
|
||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia) : base(kind)
|
GreenNode? trailingTrivia) : base(kind)
|
||||||
{
|
{
|
||||||
_text = base.Text;
|
_text = base.Text;
|
||||||
LeadingTriviaCore = leadingTrivia;
|
LeadingTriviaCore = leadingTrivia;
|
||||||
TrailingTriviaCore = trailingTrivia;
|
TrailingTriviaCore = trailingTrivia;
|
||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.FullWidth ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.FullWidth ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SyntaxTokenWithTrivia(
|
public SyntaxTokenWithTrivia(
|
||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
string text,
|
string text,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
GreenNode? trailingTrivia,
|
||||||
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
{
|
{
|
||||||
_text = text;
|
_text = text;
|
||||||
LeadingTriviaCore = leadingTrivia;
|
LeadingTriviaCore = leadingTrivia;
|
||||||
TrailingTriviaCore = trailingTrivia;
|
TrailingTriviaCore = trailingTrivia;
|
||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.FullWidth ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.FullWidth ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SyntaxTokenWithTrivia(
|
public SyntaxTokenWithTrivia(
|
||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
GreenNode? trailingTrivia,
|
||||||
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
TokenDiagnostic[] diagnostics) : base(kind, diagnostics)
|
||||||
{
|
{
|
||||||
_text = base.Text;
|
_text = base.Text;
|
||||||
LeadingTriviaCore = leadingTrivia;
|
LeadingTriviaCore = leadingTrivia;
|
||||||
TrailingTriviaCore = trailingTrivia;
|
TrailingTriviaCore = trailingTrivia;
|
||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.FullWidth ?? 0) + (_text?.Length ?? 0) + (trailingTrivia?.FullWidth ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||||
{
|
{
|
||||||
if (leading)
|
if (leading && LeadingTrivia is SyntaxList<SyntaxTrivia> leadingTrivia)
|
||||||
{
|
{
|
||||||
foreach (var trivia in LeadingTrivia)
|
for (var i = 0; i < leadingTrivia.Length; i++)
|
||||||
{
|
{
|
||||||
writer.Write(trivia.Text);
|
leadingTrivia[i].WriteTriviaTo(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base.WriteTokenTo(writer, leading, trailing);
|
base.WriteTokenTo(writer, leading, trailing);
|
||||||
if (trailing)
|
if (trailing && TrailingTrivia is SyntaxList<SyntaxTrivia> trailingTrivia)
|
||||||
{
|
{
|
||||||
foreach (var trivia in TrailingTrivia)
|
for (var i = 0; i < trailingTrivia.Length; i++)
|
||||||
{
|
{
|
||||||
writer.Write(trivia.Text);
|
trailingTrivia[i].WriteTriviaTo(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,9 +84,9 @@ namespace Parser.Internal
|
|||||||
return new SyntaxTokenWithTrivia(Kind, _text, LeadingTrivia, TrailingTrivia, diagnostics);
|
return new SyntaxTokenWithTrivia(Kind, _text, LeadingTrivia, TrailingTrivia, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore { get; }
|
public override GreenNode? LeadingTriviaCore { get; }
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore { get; }
|
public override GreenNode? TrailingTriviaCore { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SyntaxTokenWithValue<T> : SyntaxToken
|
internal class SyntaxTokenWithValue<T> : SyntaxToken
|
||||||
@ -138,46 +137,47 @@ namespace Parser.Internal
|
|||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
string text,
|
string text,
|
||||||
T value,
|
T value,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia) : base(kind, text, value)
|
GreenNode? trailingTrivia)
|
||||||
|
: base(kind, text, value)
|
||||||
{
|
{
|
||||||
LeadingTriviaCore = leadingTrivia;
|
LeadingTriviaCore = leadingTrivia;
|
||||||
TrailingTriviaCore = trailingTrivia;
|
TrailingTriviaCore = trailingTrivia;
|
||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.FullWidth ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.FullWidth ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SyntaxTokenWithValueAndTrivia(
|
public SyntaxTokenWithValueAndTrivia(
|
||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
string text,
|
string text,
|
||||||
T value,
|
T value,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
GreenNode? trailingTrivia,
|
||||||
TokenDiagnostic[] diagnostics) : base(kind, text, value, diagnostics)
|
TokenDiagnostic[] diagnostics) : base(kind, text, value, diagnostics)
|
||||||
{
|
{
|
||||||
LeadingTriviaCore = leadingTrivia;
|
LeadingTriviaCore = leadingTrivia;
|
||||||
TrailingTriviaCore = trailingTrivia;
|
TrailingTriviaCore = trailingTrivia;
|
||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.FullWidth ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.FullWidth ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore { get; }
|
public override GreenNode? LeadingTriviaCore { get; }
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore { get; }
|
public override GreenNode? TrailingTriviaCore { get; }
|
||||||
|
|
||||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||||
{
|
{
|
||||||
if (leading)
|
if (leading && LeadingTrivia is SyntaxList<SyntaxTrivia> leadingTrivia)
|
||||||
{
|
{
|
||||||
foreach (var trivia in LeadingTrivia)
|
for (var i = 0; i < leadingTrivia.Length; i++)
|
||||||
{
|
{
|
||||||
writer.Write(trivia.Text);
|
leadingTrivia[i].WriteTriviaTo(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base.WriteTokenTo(writer, leading, trailing);
|
base.WriteTokenTo(writer, leading, trailing);
|
||||||
if (trailing)
|
if (trailing && TrailingTrivia is SyntaxList<SyntaxTrivia> trailingTrivia)
|
||||||
{
|
{
|
||||||
foreach (var trivia in TrailingTrivia)
|
for (var i = 0; i < trailingTrivia.Length; i++)
|
||||||
{
|
{
|
||||||
writer.Write(trivia.Text);
|
trailingTrivia[i].WriteTriviaTo(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,49 +220,49 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
internal class SyntaxIdentifierWithTrivia : SyntaxIdentifier
|
internal class SyntaxIdentifierWithTrivia : SyntaxIdentifier
|
||||||
{
|
{
|
||||||
private readonly IReadOnlyList<SyntaxTrivia> _leadingTrivia;
|
private readonly GreenNode? _leadingTrivia;
|
||||||
private readonly IReadOnlyList<SyntaxTrivia> _trailingTrivia;
|
private readonly GreenNode? _trailingTrivia;
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => _leadingTrivia;
|
public override GreenNode? LeadingTriviaCore => _leadingTrivia;
|
||||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => _trailingTrivia;
|
public override GreenNode? TrailingTriviaCore => _trailingTrivia;
|
||||||
|
|
||||||
public SyntaxIdentifierWithTrivia(
|
public SyntaxIdentifierWithTrivia(
|
||||||
string text,
|
string text,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia
|
GreenNode? trailingTrivia)
|
||||||
) : base(text)
|
: base(text)
|
||||||
{
|
{
|
||||||
_leadingTrivia = leadingTrivia;
|
_leadingTrivia = leadingTrivia;
|
||||||
_trailingTrivia = trailingTrivia;
|
_trailingTrivia = trailingTrivia;
|
||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.FullWidth ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.FullWidth ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SyntaxIdentifierWithTrivia(
|
public SyntaxIdentifierWithTrivia(
|
||||||
string text,
|
string text,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
GreenNode? trailingTrivia,
|
||||||
TokenDiagnostic[] diagnostics) : base(text, diagnostics)
|
TokenDiagnostic[] diagnostics) : base(text, diagnostics)
|
||||||
{
|
{
|
||||||
_leadingTrivia = leadingTrivia;
|
_leadingTrivia = leadingTrivia;
|
||||||
_trailingTrivia = trailingTrivia;
|
_trailingTrivia = trailingTrivia;
|
||||||
_fullWidth = (leadingTrivia?.Sum(t => t.FullWidth) ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.Sum(t => t.FullWidth) ?? 0);
|
_fullWidth = (leadingTrivia?.FullWidth ?? 0) + (text?.Length ?? 0) + (trailingTrivia?.FullWidth ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||||
{
|
{
|
||||||
if (leading)
|
if (leading && LeadingTrivia is SyntaxList<SyntaxTrivia> leadingTrivia)
|
||||||
{
|
{
|
||||||
foreach (var trivia in LeadingTrivia)
|
for (var i = 0; i < leadingTrivia.Length; i++)
|
||||||
{
|
{
|
||||||
writer.Write(trivia.Text);
|
leadingTrivia[i].WriteTriviaTo(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base.WriteTokenTo(writer, leading, trailing);
|
base.WriteTokenTo(writer, leading, trailing);
|
||||||
if (trailing)
|
if (trailing && TrailingTrivia is SyntaxList<SyntaxTrivia> trailingTrivia)
|
||||||
{
|
{
|
||||||
foreach (var trivia in TrailingTrivia)
|
for (var i = 0; i < trailingTrivia.Length; i++)
|
||||||
{
|
{
|
||||||
writer.Write(trivia.Text);
|
trailingTrivia[i].WriteTriviaTo(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,8 +280,8 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
public MissingTokenWithTrivia(
|
public MissingTokenWithTrivia(
|
||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia
|
GreenNode? trailingTrivia
|
||||||
) : base(kind, leadingTrivia, trailingTrivia)
|
) : base(kind, leadingTrivia, trailingTrivia)
|
||||||
{
|
{
|
||||||
_isMissing = true;
|
_isMissing = true;
|
||||||
@ -289,8 +289,8 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
public MissingTokenWithTrivia(
|
public MissingTokenWithTrivia(
|
||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
GreenNode? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia,
|
GreenNode? trailingTrivia,
|
||||||
TokenDiagnostic[] diagnostics) : base(kind, leadingTrivia, trailingTrivia, diagnostics)
|
TokenDiagnostic[] diagnostics) : base(kind, leadingTrivia, trailingTrivia, diagnostics)
|
||||||
{
|
{
|
||||||
_isMissing = true;
|
_isMissing = true;
|
||||||
@ -312,7 +312,7 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static SyntaxToken NoneToken => new MissingTokenWithTrivia(TokenKind.None, s_EmptySyntaxTriviaList, s_EmptySyntaxTriviaList);
|
internal static SyntaxToken NoneToken => new MissingTokenWithTrivia(TokenKind.None, null, null);
|
||||||
|
|
||||||
public virtual object? Value => null;
|
public virtual object? Value => null;
|
||||||
|
|
||||||
@ -320,8 +320,8 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
public virtual int Width => Text.Length;
|
public virtual int Width => Text.Length;
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => s_EmptySyntaxTriviaList;
|
public override GreenNode? LeadingTriviaCore => null;
|
||||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => s_EmptySyntaxTriviaList;
|
public override GreenNode? TrailingTriviaCore => null;
|
||||||
|
|
||||||
public override GreenNode? GetSlot(int i)
|
public override GreenNode? GetSlot(int i)
|
||||||
{
|
{
|
||||||
|
@ -20,6 +20,7 @@ namespace Parser.Internal
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override string Text => _text;
|
public override string Text => _text;
|
||||||
|
public override string FullText => _text;
|
||||||
public int Width => _text.Length;
|
public int Width => _text.Length;
|
||||||
|
|
||||||
public override GreenNode? GetSlot(int i)
|
public override GreenNode? GetSlot(int i)
|
||||||
@ -40,12 +41,17 @@ namespace Parser.Internal
|
|||||||
writer.Write(_text);
|
writer.Write(_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void WriteTokenTo(TextWriter writer, bool leading, bool trailing)
|
||||||
|
{
|
||||||
|
writer.Write(_text);
|
||||||
|
}
|
||||||
|
|
||||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
{
|
{
|
||||||
return new SyntaxTrivia(Kind, _text, diagnostics);
|
return new SyntaxTrivia(Kind, _text, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IReadOnlyList<SyntaxTrivia> LeadingTriviaCore => new List<SyntaxTrivia>();
|
public override GreenNode? LeadingTriviaCore => null;
|
||||||
public override IReadOnlyList<SyntaxTrivia> TrailingTriviaCore => new List<SyntaxTrivia>();
|
public override GreenNode? TrailingTriviaCore => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,6 +13,16 @@ namespace Parser.Internal
|
|||||||
TokenKind kind,
|
TokenKind kind,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia)
|
IReadOnlyList<SyntaxTrivia> trailingTrivia)
|
||||||
|
{
|
||||||
|
var leading = leadingTrivia.Count > 0 ? SyntaxList<SyntaxTrivia>.List(leadingTrivia) : null;
|
||||||
|
var trailing = trailingTrivia.Count > 0 ? SyntaxList<SyntaxTrivia>.List(trailingTrivia) : null;
|
||||||
|
return new SyntaxToken.SyntaxTokenWithTrivia(kind, leading, trailing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SyntaxToken CreateTokenWithTrivia(
|
||||||
|
TokenKind kind,
|
||||||
|
GreenNode? leadingTrivia,
|
||||||
|
GreenNode? trailingTrivia)
|
||||||
{
|
{
|
||||||
return new SyntaxToken.SyntaxTokenWithTrivia(kind, leadingTrivia, trailingTrivia);
|
return new SyntaxToken.SyntaxTokenWithTrivia(kind, leadingTrivia, trailingTrivia);
|
||||||
}
|
}
|
||||||
@ -21,6 +31,16 @@ namespace Parser.Internal
|
|||||||
string text,
|
string text,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia)
|
IReadOnlyList<SyntaxTrivia> trailingTrivia)
|
||||||
|
{
|
||||||
|
var leading = leadingTrivia.Count > 0 ? SyntaxList<SyntaxTrivia>.List(leadingTrivia) : null;
|
||||||
|
var trailing = trailingTrivia.Count > 0 ? SyntaxList<SyntaxTrivia>.List(trailingTrivia) : null;
|
||||||
|
return new SyntaxToken.SyntaxIdentifierWithTrivia(text, leading, trailing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SyntaxToken CreateIdentifier(
|
||||||
|
string text,
|
||||||
|
GreenNode? leadingTrivia,
|
||||||
|
GreenNode? trailingTrivia)
|
||||||
{
|
{
|
||||||
return new SyntaxToken.SyntaxIdentifierWithTrivia(text, leadingTrivia, trailingTrivia);
|
return new SyntaxToken.SyntaxIdentifierWithTrivia(text, leadingTrivia, trailingTrivia);
|
||||||
}
|
}
|
||||||
@ -31,6 +51,18 @@ namespace Parser.Internal
|
|||||||
T value,
|
T value,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia)
|
IReadOnlyList<SyntaxTrivia> trailingTrivia)
|
||||||
|
{
|
||||||
|
var leading = leadingTrivia.Count > 0 ? SyntaxList<SyntaxTrivia>.List(leadingTrivia) : null;
|
||||||
|
var trailing = trailingTrivia.Count > 0 ? SyntaxList<SyntaxTrivia>.List(trailingTrivia) : null;
|
||||||
|
return new SyntaxToken.SyntaxTokenWithValueAndTrivia<T>(kind, text, value, leading, trailing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SyntaxToken CreateTokenWithValueAndTrivia<T>(
|
||||||
|
TokenKind kind,
|
||||||
|
string text,
|
||||||
|
T value,
|
||||||
|
GreenNode? leadingTrivia,
|
||||||
|
GreenNode? trailingTrivia)
|
||||||
{
|
{
|
||||||
return new SyntaxToken.SyntaxTokenWithValueAndTrivia<T>(kind, text, value, leadingTrivia, trailingTrivia);
|
return new SyntaxToken.SyntaxTokenWithValueAndTrivia<T>(kind, text, value, leadingTrivia, trailingTrivia);
|
||||||
}
|
}
|
||||||
@ -40,6 +72,22 @@ namespace Parser.Internal
|
|||||||
string value,
|
string value,
|
||||||
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
IReadOnlyList<SyntaxTrivia> leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia> trailingTrivia)
|
IReadOnlyList<SyntaxTrivia> trailingTrivia)
|
||||||
|
{
|
||||||
|
var leading = leadingTrivia.Count > 0 ? SyntaxList<SyntaxTrivia>.List(leadingTrivia) : null;
|
||||||
|
var trailing = trailingTrivia.Count > 0 ? SyntaxList<SyntaxTrivia>.List(trailingTrivia) : null;
|
||||||
|
return new SyntaxToken.SyntaxTokenWithValueAndTrivia<string>(
|
||||||
|
TokenKind.UnquotedStringLiteralToken,
|
||||||
|
text,
|
||||||
|
value,
|
||||||
|
leading,
|
||||||
|
trailing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SyntaxToken CreateUnquotedStringLiteral(
|
||||||
|
string text,
|
||||||
|
string value,
|
||||||
|
GreenNode? leadingTrivia,
|
||||||
|
GreenNode? trailingTrivia)
|
||||||
{
|
{
|
||||||
return new SyntaxToken.SyntaxTokenWithValueAndTrivia<string>(
|
return new SyntaxToken.SyntaxTokenWithValueAndTrivia<string>(
|
||||||
TokenKind.UnquotedStringLiteralToken,
|
TokenKind.UnquotedStringLiteralToken,
|
||||||
@ -54,7 +102,9 @@ namespace Parser.Internal
|
|||||||
IReadOnlyList<SyntaxTrivia>? leadingTrivia,
|
IReadOnlyList<SyntaxTrivia>? leadingTrivia,
|
||||||
IReadOnlyList<SyntaxTrivia>? trailingTrivia)
|
IReadOnlyList<SyntaxTrivia>? trailingTrivia)
|
||||||
{
|
{
|
||||||
return new SyntaxToken.MissingTokenWithTrivia(kind, leadingTrivia ?? SyntaxToken.s_EmptySyntaxTriviaList, trailingTrivia ?? SyntaxToken.s_EmptySyntaxTriviaList);
|
var leading = (leadingTrivia is { } l && l.Count > 0) ? SyntaxList<SyntaxTrivia>.List(leadingTrivia) : null;
|
||||||
|
var trailing = (trailingTrivia is { } c && c.Count > 0) ? SyntaxList<SyntaxTrivia>.List(trailingTrivia) : null;
|
||||||
|
return new SyntaxToken.MissingTokenWithTrivia(kind, leading, trailing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
using Parser.Binding;
|
using Parser.Binding;
|
||||||
using System.Collections;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -10,6 +10,7 @@ namespace Parser.Lowering
|
|||||||
internal class Lowerer : BoundTreeRewriter
|
internal class Lowerer : BoundTreeRewriter
|
||||||
{
|
{
|
||||||
private int _labelNumber = 0;
|
private int _labelNumber = 0;
|
||||||
|
private int _localVariableNumber = 0;
|
||||||
|
|
||||||
private Lowerer()
|
private Lowerer()
|
||||||
{
|
{
|
||||||
@ -21,6 +22,12 @@ namespace Parser.Lowering
|
|||||||
return new BoundLabel(name);
|
return new BoundLabel(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TypedVariableSymbol GenerateTypedLocalVariable(TypeSymbol typeSymbol)
|
||||||
|
{
|
||||||
|
var name = $"#{++_localVariableNumber}";
|
||||||
|
return new TypedVariableSymbol(name, typeSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
public override BoundStatement RewriteIfStatement(BoundIfStatement node)
|
public override BoundStatement RewriteIfStatement(BoundIfStatement node)
|
||||||
{
|
{
|
||||||
// if cond
|
// if cond
|
||||||
@ -80,6 +87,116 @@ namespace Parser.Lowering
|
|||||||
return RewriteBlockStatement(Block(node.Syntax, builder.ToArray()));
|
return RewriteBlockStatement(Block(node.Syntax, builder.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override BoundStatement RewriteWhileStatement(BoundWhileStatement node)
|
||||||
|
{
|
||||||
|
// while cond
|
||||||
|
// body
|
||||||
|
// end
|
||||||
|
//
|
||||||
|
// |
|
||||||
|
// |
|
||||||
|
// V
|
||||||
|
//
|
||||||
|
// LabelLoop:
|
||||||
|
// gotoFalse cond LabelEnd
|
||||||
|
// body
|
||||||
|
// goto LabelLoop
|
||||||
|
// LabelEnd:
|
||||||
|
var labelLoop = GenerateLabel();
|
||||||
|
var labelEnd = GenerateLabel();
|
||||||
|
var result = Block(
|
||||||
|
node.Syntax,
|
||||||
|
// LabelLoop:
|
||||||
|
LabelStatement(node.Syntax, labelLoop),
|
||||||
|
// gotoFalse cond LabelEnd
|
||||||
|
GotoIfFalse(
|
||||||
|
node.Syntax,
|
||||||
|
node.Condition,
|
||||||
|
labelEnd),
|
||||||
|
// body
|
||||||
|
node.Body,
|
||||||
|
// goto LabelLoop
|
||||||
|
Goto(node.Syntax, labelLoop),
|
||||||
|
// LabelEnd:
|
||||||
|
LabelStatement(node.Syntax, labelEnd));
|
||||||
|
return RewriteBlockStatement(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BoundStatement RewriteForStatement(BoundForStatement node)
|
||||||
|
{
|
||||||
|
// for i = expr
|
||||||
|
// body
|
||||||
|
// end
|
||||||
|
//
|
||||||
|
// |
|
||||||
|
// |
|
||||||
|
// V
|
||||||
|
//
|
||||||
|
// #array = expr
|
||||||
|
// #length = len(#array)
|
||||||
|
// #index = 0
|
||||||
|
// while #index < #length
|
||||||
|
// i = #array(#index);
|
||||||
|
// body
|
||||||
|
// #index = #index + 1
|
||||||
|
var localArray = GenerateTypedLocalVariable(TypeSymbol.MObject);
|
||||||
|
var localLength = GenerateTypedLocalVariable(TypeSymbol.Int);
|
||||||
|
var localIndex = GenerateTypedLocalVariable(TypeSymbol.Int);
|
||||||
|
var whileBody = Block(
|
||||||
|
node.Syntax,
|
||||||
|
// i = #array(#index);
|
||||||
|
ExpressionStatement(
|
||||||
|
node.Syntax,
|
||||||
|
Assignment(
|
||||||
|
node.Syntax,
|
||||||
|
node.LoopVariable,
|
||||||
|
FunctionCall(
|
||||||
|
node.Syntax,
|
||||||
|
TypedVariableExpression(node.Syntax, localArray),
|
||||||
|
new[] { (BoundExpression)TypedVariableExpression(node.Syntax, localIndex) }.ToImmutableArray())),
|
||||||
|
discardResult: true),
|
||||||
|
// body
|
||||||
|
node.Body,
|
||||||
|
// #index = #index + 1;
|
||||||
|
ExpressionStatement(
|
||||||
|
node.Syntax,
|
||||||
|
Assignment(
|
||||||
|
node.Syntax,
|
||||||
|
TypedVariableExpression(node.Syntax, localIndex),
|
||||||
|
BinaryOperation(
|
||||||
|
node.Syntax,
|
||||||
|
TypedVariableExpression(node.Syntax, localIndex),
|
||||||
|
BoundBinaryOperator.GetOperator(TokenKind.PlusToken, TypeSymbol.Int, TypeSymbol.Int)!,
|
||||||
|
NumberIntLiteral(node.Syntax, 1))),
|
||||||
|
discardResult: true));
|
||||||
|
|
||||||
|
var result = Block(
|
||||||
|
node.Syntax,
|
||||||
|
// #array = expr
|
||||||
|
TypedVariableDeclaration(node.Syntax, localArray, node.LoopedExpression),
|
||||||
|
// #length = len(#array)
|
||||||
|
TypedVariableDeclaration(
|
||||||
|
node.Syntax,
|
||||||
|
localLength,
|
||||||
|
FunctionCall(
|
||||||
|
node.Syntax,
|
||||||
|
Identifier(node.Syntax, "len"),
|
||||||
|
new[] { (BoundExpression)TypedVariableExpression(node.Syntax, localArray) }.ToImmutableArray())),
|
||||||
|
// #index = 0
|
||||||
|
TypedVariableDeclaration(node.Syntax, localIndex, NumberIntLiteral(node.Syntax, 0)),
|
||||||
|
// while #index < #length
|
||||||
|
// whileBody
|
||||||
|
WhileStatement(
|
||||||
|
node.Syntax,
|
||||||
|
BinaryOperation(
|
||||||
|
node.Syntax,
|
||||||
|
TypedVariableExpression(node.Syntax, localIndex),
|
||||||
|
BoundBinaryOperator.GetOperator(TokenKind.LessToken, TypeSymbol.Int, TypeSymbol.Int)!,
|
||||||
|
TypedVariableExpression(node.Syntax, localLength)),
|
||||||
|
whileBody));
|
||||||
|
return RewriteBlockStatement(result);
|
||||||
|
}
|
||||||
|
|
||||||
public static BoundBlockStatement Lower(BoundStatement statement)
|
public static BoundBlockStatement Lower(BoundStatement statement)
|
||||||
{
|
{
|
||||||
var lowerer = new Lowerer();
|
var lowerer = new Lowerer();
|
||||||
|
40
Parser/MFunctions/MHelpers.cs
Normal file
40
Parser/MFunctions/MHelpers.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using Parser.Objects;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Parser.MFunctions
|
||||||
|
{
|
||||||
|
public static class MHelpers
|
||||||
|
{
|
||||||
|
public static void Disp(MObject? obj)
|
||||||
|
{
|
||||||
|
if (obj is not null)
|
||||||
|
{
|
||||||
|
Console.WriteLine(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Len(MObject obj)
|
||||||
|
{
|
||||||
|
return obj switch
|
||||||
|
{
|
||||||
|
MDoubleMatrix m => m.RowCount * m.ColumnCount,
|
||||||
|
MDoubleNumber _ => 1,
|
||||||
|
MLogical _ => 1,
|
||||||
|
MCharArray c => c.Chars.Length,
|
||||||
|
_ => throw new System.Exception($"Unknown MObject type {obj.GetType()}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ToBool(MObject operand)
|
||||||
|
{
|
||||||
|
return operand switch
|
||||||
|
{
|
||||||
|
MDoubleNumber { Value: var value } => value != 0.0,
|
||||||
|
MLogical { Value: var value } => value,
|
||||||
|
MCharArray { Chars: var value } => value.Length > 0,
|
||||||
|
MDoubleMatrix m => m.RowCount > 0 && m.ColumnCount > 0,
|
||||||
|
_ => throw new System.Exception($"Unknown MObject type {operand.GetType()}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,34 @@
|
|||||||
using Parser.Objects;
|
using Parser.Objects;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Parser.MFunctions
|
namespace Parser.MFunctions
|
||||||
{
|
{
|
||||||
public static class MOperations
|
public static class MOperations
|
||||||
{
|
{
|
||||||
|
public static MObject? Colon(MObject left, MObject right)
|
||||||
|
{
|
||||||
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
|
&& right is MDoubleNumber { Value: var rValue })
|
||||||
|
{
|
||||||
|
var array = CreateRangeMatrix(lValue, rValue);
|
||||||
|
return MObject.CreateDoubleMatrix(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double[,] CreateRangeMatrix(double lValue, double rValue)
|
||||||
|
{
|
||||||
|
var length = (int)Math.Round(rValue - lValue) + 1;
|
||||||
|
var result = new double[1, length];
|
||||||
|
for (var i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
result[0, i] = lValue + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static MObject? Plus(MObject left, MObject right)
|
public static MObject? Plus(MObject left, MObject right)
|
||||||
{
|
{
|
||||||
if (left is MDoubleNumber { Value: var lValue }
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
@ -101,5 +126,17 @@ namespace Parser.MFunctions
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MObject? ArraySlice(MObject array, MObject range)
|
||||||
|
{
|
||||||
|
if (array is MDoubleMatrix m
|
||||||
|
&& range is MDoubleNumber { Value: var doubleIndex })
|
||||||
|
{
|
||||||
|
var index = (int)doubleIndex;
|
||||||
|
return MObject.CreateDoubleNumber(m[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
Parser/Objects/MDoubleMatrix.cs
Normal file
48
Parser/Objects/MDoubleMatrix.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Parser.Objects
|
||||||
|
{
|
||||||
|
public class MDoubleMatrix : MObject
|
||||||
|
{
|
||||||
|
private MDoubleMatrix(double[,] matrix)
|
||||||
|
{
|
||||||
|
Matrix = matrix;
|
||||||
|
RowCount = matrix.GetLength(0);
|
||||||
|
ColumnCount = matrix.GetLength(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double[,] Matrix { get; }
|
||||||
|
|
||||||
|
public int RowCount { get; }
|
||||||
|
|
||||||
|
public int ColumnCount { get; }
|
||||||
|
|
||||||
|
public ref double this[int i, int j] => ref Matrix[i, j];
|
||||||
|
|
||||||
|
public ref double this[int i] => ref Matrix[i % RowCount, i / RowCount];
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
for (var i = 0; i < RowCount; i++)
|
||||||
|
{
|
||||||
|
for (var j = 0; j < ColumnCount; j++)
|
||||||
|
{
|
||||||
|
if (j > 0)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
}
|
||||||
|
sb.Append(Matrix[i, j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MDoubleMatrix Create(double[,] matrix)
|
||||||
|
{
|
||||||
|
return new MDoubleMatrix(matrix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
namespace Parser.Objects
|
using System;
|
||||||
|
|
||||||
|
namespace Parser.Objects
|
||||||
{
|
{
|
||||||
public abstract class MObject
|
public abstract class MObject
|
||||||
{
|
{
|
||||||
@ -7,11 +9,26 @@
|
|||||||
return MDoubleNumber.Create(value);
|
return MDoubleNumber.Create(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MDoubleNumber CreateIntNumber(int value)
|
||||||
|
{
|
||||||
|
return MDoubleNumber.Create(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MDoubleMatrix CreateDoubleMatrix(double[,] matrix)
|
||||||
|
{
|
||||||
|
return MDoubleMatrix.Create(matrix);
|
||||||
|
}
|
||||||
|
|
||||||
public static MCharArray CreateCharArray(char[] chars)
|
public static MCharArray CreateCharArray(char[] chars)
|
||||||
{
|
{
|
||||||
return MCharArray.Create(chars);
|
return MCharArray.Create(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MCharArray CreateCharArray(string s)
|
||||||
|
{
|
||||||
|
return MCharArray.Create(s.ToCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
public static MLogical CreateLogical(bool value)
|
public static MLogical CreateLogical(bool value)
|
||||||
{
|
{
|
||||||
return MLogical.Create(value);
|
return MLogical.Create(value);
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>preview</LangVersion>
|
<LangVersion>preview</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
|
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
|
||||||
|
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Syntax xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
<Syntax xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
<Class Name="FileSyntaxNode" BaseClass="SyntaxNode" Kind="File">
|
<Class Name="FileSyntaxNode" BaseClass="SyntaxNode" Kind="File">
|
||||||
<Field Type="BlockStatementSyntaxNode" Name="body" />
|
<Field Type="BlockStatementSyntaxNode" Name="body" Nullable="true"/>
|
||||||
<Field Type="SyntaxToken" Name="endOfFile" />
|
<Field Type="SyntaxToken" Name="endOfFile" />
|
||||||
</Class>
|
</Class>
|
||||||
<Class Name="BlockStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="BlockStatement">
|
<Class Name="BlockStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="BlockStatement">
|
||||||
@ -88,6 +88,10 @@
|
|||||||
</Class>
|
</Class>
|
||||||
<Class Name="ExpressionStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ExpressionStatement">
|
<Class Name="ExpressionStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="ExpressionStatement">
|
||||||
<Field Type="ExpressionSyntaxNode" Name="expression" />
|
<Field Type="ExpressionSyntaxNode" Name="expression" />
|
||||||
|
<Field Type="TrailingSemicolonSyntaxNode" Name="semicolon" Nullable="true" />
|
||||||
|
</Class>
|
||||||
|
<Class Name="TrailingSemicolonSyntaxNode" BaseClass="SyntaxNode" Kind="TrailingSemicolon">
|
||||||
|
<Field Type="SyntaxToken" Name="semicolon" />
|
||||||
</Class>
|
</Class>
|
||||||
<Class Name="EmptyStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="EmptyStatement">
|
<Class Name="EmptyStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="EmptyStatement">
|
||||||
<Field Type="SyntaxToken" Name="semicolon" />
|
<Field Type="SyntaxToken" Name="semicolon" />
|
||||||
|
27
Parser/SyntaxNavigator.cs
Normal file
27
Parser/SyntaxNavigator.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Parser
|
||||||
|
{
|
||||||
|
public class SyntaxNavigator
|
||||||
|
{
|
||||||
|
public static SyntaxNavigator Singleton = new SyntaxNavigator();
|
||||||
|
|
||||||
|
public IEnumerable<SyntaxToken> EnumerateTokens(SyntaxNode node)
|
||||||
|
{
|
||||||
|
foreach (var child in node.GetChildNodesAndTokens())
|
||||||
|
{
|
||||||
|
if (child.IsNode)
|
||||||
|
{
|
||||||
|
foreach (var token in EnumerateTokens(child.AsNode()!))
|
||||||
|
{
|
||||||
|
yield return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (child.IsToken)
|
||||||
|
{
|
||||||
|
yield return child.AsToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,12 +16,12 @@ namespace Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockStatementSyntaxNode Body
|
public BlockStatementSyntaxNode? Body
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var red = this.GetRed(ref this._body!, 0);
|
var red = this.GetRed(ref this._body, 0);
|
||||||
return red is null ? throw new System.Exception("body cannot be null.") : (BlockStatementSyntaxNode)red;
|
return red is null ? default : (BlockStatementSyntaxNode)red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ namespace Parser
|
|||||||
{
|
{
|
||||||
return i switch
|
return i switch
|
||||||
{
|
{
|
||||||
0 => GetRed(ref _body!, 0), _ => null
|
0 => GetRed(ref _body, 0), _ => null
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
;
|
||||||
@ -852,6 +852,7 @@ namespace Parser
|
|||||||
public class ExpressionStatementSyntaxNode : StatementSyntaxNode
|
public class ExpressionStatementSyntaxNode : StatementSyntaxNode
|
||||||
{
|
{
|
||||||
private SyntaxNode? _expression;
|
private SyntaxNode? _expression;
|
||||||
|
private SyntaxNode? _semicolon;
|
||||||
internal ExpressionStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position): base(parent, green, position)
|
internal ExpressionStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position): base(parent, green, position)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -865,11 +866,20 @@ namespace Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TrailingSemicolonSyntaxNode? Semicolon
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var red = this.GetRed(ref this._semicolon, 1);
|
||||||
|
return red is null ? default : (TrailingSemicolonSyntaxNode)red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal override SyntaxNode? GetNode(int i)
|
internal override SyntaxNode? GetNode(int i)
|
||||||
{
|
{
|
||||||
return i switch
|
return i switch
|
||||||
{
|
{
|
||||||
0 => GetRed(ref _expression!, 0), _ => null
|
0 => GetRed(ref _expression!, 0), 1 => GetRed(ref _semicolon, 1), _ => null
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
;
|
||||||
@ -881,6 +891,36 @@ namespace Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TrailingSemicolonSyntaxNode : SyntaxNode
|
||||||
|
{
|
||||||
|
internal TrailingSemicolonSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position): base(parent, green, position)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SyntaxToken Semicolon
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new SyntaxToken(this, ((Parser.Internal.TrailingSemicolonSyntaxNode)_green)._semicolon, this.GetChildPosition(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override SyntaxNode? GetNode(int i)
|
||||||
|
{
|
||||||
|
return i switch
|
||||||
|
{
|
||||||
|
_ => null
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Accept(SyntaxVisitor visitor)
|
||||||
|
{
|
||||||
|
visitor.VisitTrailingSemicolon(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class EmptyStatementSyntaxNode : StatementSyntaxNode
|
public class EmptyStatementSyntaxNode : StatementSyntaxNode
|
||||||
{
|
{
|
||||||
internal EmptyStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position): base(parent, green, position)
|
internal EmptyStatementSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position): base(parent, green, position)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using Parser.Internal;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Parser
|
namespace Parser
|
||||||
@ -13,6 +13,7 @@ namespace Parser
|
|||||||
_parent = parent;
|
_parent = parent;
|
||||||
_green = green;
|
_green = green;
|
||||||
Position = position;
|
Position = position;
|
||||||
|
FullSpan = new TextSpan(Position, green.FullWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
private protected SyntaxNode(Internal.GreenNode green, int position)
|
private protected SyntaxNode(Internal.GreenNode green, int position)
|
||||||
@ -20,6 +21,7 @@ namespace Parser
|
|||||||
_parent = this;
|
_parent = this;
|
||||||
_green = green;
|
_green = green;
|
||||||
Position = position;
|
Position = position;
|
||||||
|
FullSpan = new TextSpan(Position, green.FullWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TokenKind Kind => _green.Kind;
|
public TokenKind Kind => _green.Kind;
|
||||||
@ -35,6 +37,19 @@ namespace Parser
|
|||||||
|
|
||||||
public int Position { get; }
|
public int Position { get; }
|
||||||
|
|
||||||
|
public TextSpan FullSpan { get; }
|
||||||
|
|
||||||
|
public TextSpan Span => CalculateSpan();
|
||||||
|
|
||||||
|
private TextSpan CalculateSpan()
|
||||||
|
{
|
||||||
|
var leadingTriviaWidth = LeadingTrivia?.Width ?? 0;
|
||||||
|
var trailingTriviaWidth = TrailingTrivia?.Width ?? 0;
|
||||||
|
return new TextSpan(Position + leadingTriviaWidth, _green.FullWidth - leadingTriviaWidth - trailingTriviaWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int FullWidth => _green.FullWidth;
|
||||||
|
|
||||||
internal int GetChildPosition(int slot)
|
internal int GetChildPosition(int slot)
|
||||||
{
|
{
|
||||||
var result = Position;
|
var result = Position;
|
||||||
@ -75,26 +90,32 @@ namespace Parser
|
|||||||
|
|
||||||
public virtual string FullText => _green.FullText;
|
public virtual string FullText => _green.FullText;
|
||||||
|
|
||||||
public int FullWidth => _green.FullWidth;
|
public virtual SyntaxTriviaList? LeadingTrivia
|
||||||
|
|
||||||
public virtual IReadOnlyList<SyntaxTrivia> LeadingTrivia
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var p = Parent;
|
return GetFirstToken()?.LeadingTrivia;
|
||||||
return _green.LeadingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual IReadOnlyList<SyntaxTrivia> TrailingTrivia
|
public virtual SyntaxTriviaList? TrailingTrivia
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var p = Parent;
|
return GetLastToken()?.TrailingTrivia;
|
||||||
return _green.TrailingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SyntaxToken? GetFirstToken()
|
||||||
|
{
|
||||||
|
return SyntaxNavigator.Singleton.EnumerateTokens(this).Select(t => (SyntaxToken?)t).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SyntaxToken? GetLastToken()
|
||||||
|
{
|
||||||
|
return SyntaxNavigator.Singleton.EnumerateTokens(this).Select(t => (SyntaxToken?)t).LastOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void Accept(SyntaxVisitor visitor);
|
public abstract void Accept(SyntaxVisitor visitor);
|
||||||
|
|
||||||
public SyntaxDiagnostic[] GetDiagnostics()
|
public SyntaxDiagnostic[] GetDiagnostics()
|
||||||
@ -165,12 +186,16 @@ namespace Parser
|
|||||||
|
|
||||||
internal override SyntaxNode? GetNode(int index)
|
internal override SyntaxNode? GetNode(int index)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
return index switch
|
||||||
|
{
|
||||||
|
0 => GetRed(ref _file!, 0),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Accept(SyntaxVisitor visitor)
|
public override void Accept(SyntaxVisitor visitor)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
visitor.VisitRoot(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using Parser.Internal;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -22,6 +23,7 @@ namespace Parser
|
|||||||
_parent = parent;
|
_parent = parent;
|
||||||
_token = token ?? throw new ArgumentNullException(nameof(token));
|
_token = token ?? throw new ArgumentNullException(nameof(token));
|
||||||
Position = position;
|
Position = position;
|
||||||
|
FullSpan = new TextSpan(Position, token.FullWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SyntaxNode Parent => _parent;
|
public SyntaxNode Parent => _parent;
|
||||||
@ -29,6 +31,17 @@ namespace Parser
|
|||||||
|
|
||||||
public int Position { get; }
|
public int Position { get; }
|
||||||
|
|
||||||
|
public TextSpan FullSpan { get; }
|
||||||
|
|
||||||
|
public TextSpan Span => CalculateSpan();
|
||||||
|
|
||||||
|
public TextSpan CalculateSpan()
|
||||||
|
{
|
||||||
|
var leadingTriviaWidth = LeadingTrivia.Width;
|
||||||
|
var trailingTriviaWidth = TrailingTrivia.Width;
|
||||||
|
return new TextSpan(Position + leadingTriviaWidth, FullWidth - leadingTriviaWidth - trailingTriviaWidth);
|
||||||
|
}
|
||||||
|
|
||||||
public object? Value => _token.GetValue();
|
public object? Value => _token.GetValue();
|
||||||
|
|
||||||
public bool Equals(SyntaxToken other)
|
public bool Equals(SyntaxToken other)
|
||||||
@ -38,7 +51,7 @@ namespace Parser
|
|||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(null, obj)) return false;
|
if (obj is null) return false;
|
||||||
return obj is SyntaxToken token && Equals(token);
|
return obj is SyntaxToken token && Equals(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,21 +78,21 @@ namespace Parser
|
|||||||
public int FullWidth => _token.FullWidth;
|
public int FullWidth => _token.FullWidth;
|
||||||
public bool IsMissing => _token.IsMissing;
|
public bool IsMissing => _token.IsMissing;
|
||||||
|
|
||||||
public IReadOnlyList<SyntaxTrivia> LeadingTrivia
|
public SyntaxTriviaList LeadingTrivia
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var p = _parent;
|
return new SyntaxTriviaList(this, Token.LeadingTriviaCore, this.Position);
|
||||||
return _token.LeadingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<SyntaxTrivia> TrailingTrivia
|
public SyntaxTriviaList TrailingTrivia
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var p = _parent;
|
var trailingGreen = Token.TrailingTriviaCore;
|
||||||
return _token.TrailingTrivia.Select(trivia => new SyntaxTrivia(p, trivia)).ToImmutableList();
|
var trailingTriviaWidth = trailingGreen?.FullWidth ?? 0;
|
||||||
|
return new SyntaxTriviaList(this, trailingGreen, this.Position + this.FullWidth - trailingTriviaWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
Parser/SyntaxTriviaList.cs
Normal file
54
Parser/SyntaxTriviaList.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using Parser.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Parser
|
||||||
|
{
|
||||||
|
public struct SyntaxTriviaList : IReadOnlyList<SyntaxTrivia>
|
||||||
|
{
|
||||||
|
internal GreenNode? Node { get; }
|
||||||
|
|
||||||
|
internal SyntaxTriviaList(SyntaxToken token, GreenNode? node, int position)
|
||||||
|
{
|
||||||
|
Node = node;
|
||||||
|
Token = token;
|
||||||
|
Position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SyntaxToken Token { get; }
|
||||||
|
|
||||||
|
public int Position { get; }
|
||||||
|
|
||||||
|
public int Count => (Node as SyntaxList<Internal.SyntaxTrivia>)?.Length ?? 0;
|
||||||
|
|
||||||
|
public int Width => Node?.FullWidth ?? 0;
|
||||||
|
|
||||||
|
public SyntaxTrivia this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Node switch
|
||||||
|
{
|
||||||
|
SyntaxList<Internal.SyntaxTrivia> triviaList => new SyntaxTrivia(Token.Parent, triviaList[index]),
|
||||||
|
_ => throw new IndexOutOfRangeException(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FullText => Node?.FullText ?? string.Empty;
|
||||||
|
|
||||||
|
public IEnumerator<SyntaxTrivia> GetEnumerator()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
yield return this[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -83,6 +83,11 @@ namespace Parser
|
|||||||
DefaultVisit(node);
|
DefaultVisit(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void VisitTrailingSemicolon(TrailingSemicolonSyntaxNode node)
|
||||||
|
{
|
||||||
|
DefaultVisit(node);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void VisitEmptyStatement(EmptyStatementSyntaxNode node)
|
public virtual void VisitEmptyStatement(EmptyStatementSyntaxNode node)
|
||||||
{
|
{
|
||||||
DefaultVisit(node);
|
DefaultVisit(node);
|
||||||
|
@ -15,5 +15,10 @@
|
|||||||
{
|
{
|
||||||
DefaultVisit(list);
|
DefaultVisit(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void VisitRoot(RootSyntaxNode node)
|
||||||
|
{
|
||||||
|
DefaultVisit(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -135,6 +135,9 @@
|
|||||||
// a list of syntax nodes and/or tokens.
|
// a list of syntax nodes and/or tokens.
|
||||||
List,
|
List,
|
||||||
|
|
||||||
|
// a semicolon that marks expression statements with discarded results.
|
||||||
|
TrailingSemicolon,
|
||||||
|
|
||||||
|
|
||||||
// STATEMENTS
|
// STATEMENTS
|
||||||
// The name ends with "Declaration" or "Statement".
|
// The name ends with "Declaration" or "Statement".
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -11,14 +11,14 @@ namespace Semantics
|
|||||||
{
|
{
|
||||||
var name = methodDefinition.Name.Text;
|
var name = methodDefinition.Name.Text;
|
||||||
var description = "";
|
var description = "";
|
||||||
description += string.Join("", methodDefinition.LeadingTrivia.Select(x => x.FullText));
|
description += string.Join("", methodDefinition.LeadingTrivia?.Select(x => x.FullText));
|
||||||
if (methodDefinition.Body == null)
|
if (methodDefinition.Body == null)
|
||||||
{
|
{
|
||||||
description += string.Join("", methodDefinition.EndKeyword.LeadingTrivia.Select(x => x.FullText));
|
description += string.Join("", methodDefinition.EndKeyword.LeadingTrivia?.Select(x => x.FullText));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
description += string.Join("", methodDefinition.Body.LeadingTrivia.Select(x => x.FullText));
|
description += string.Join("", methodDefinition.Body.LeadingTrivia?.Select(x => x.FullText));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MMethod(name, description);
|
return new MMethod(name, description);
|
||||||
@ -28,7 +28,7 @@ namespace Semantics
|
|||||||
{
|
{
|
||||||
var name = methodDeclaration.Name.Text;
|
var name = methodDeclaration.Name.Text;
|
||||||
var description = "";
|
var description = "";
|
||||||
description += string.Join("", methodDeclaration.LeadingTrivia.Select(x => x.FullText));
|
description += string.Join("", methodDeclaration.LeadingTrivia?.Select(x => x.FullText));
|
||||||
return new MMethod(name, description);
|
return new MMethod(name, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,8 +58,7 @@ namespace Semantics
|
|||||||
|
|
||||||
public static MClass FromTree(FileSyntaxNode tree, string fileName)
|
public static MClass FromTree(FileSyntaxNode tree, string fileName)
|
||||||
{
|
{
|
||||||
var classDeclaration = tree.Body.Statements[0].AsNode() as ClassDeclarationSyntaxNode;
|
if (tree.Body.Statements[0].AsNode() is not ClassDeclarationSyntaxNode classDeclaration)
|
||||||
if (classDeclaration == null)
|
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Parser\Parser.csproj" />
|
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||||
|
@ -23,7 +23,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repl", "Repl\Repl.csproj",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MApplication", "MApplication\MApplication.csproj", "{A7EE271C-8822-43EA-BA13-5D6D5DC5B581}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MApplication", "MApplication\MApplication.csproj", "{A7EE271C-8822-43EA-BA13-5D6D5DC5B581}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cmi", "cmi\cmi.csproj", "{C2447F0B-733D-4755-A104-5B82E24D3F47}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmi", "cmi\cmi.csproj", "{C2447F0B-733D-4755-A104-5B82E24D3F47}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cmc", "cmc\cmc.csproj", "{4200B289-ED2B-4C6F-AFDF-EC91FB3837B3}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -63,6 +65,10 @@ Global
|
|||||||
{C2447F0B-733D-4755-A104-5B82E24D3F47}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C2447F0B-733D-4755-A104-5B82E24D3F47}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C2447F0B-733D-4755-A104-5B82E24D3F47}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C2447F0B-733D-4755-A104-5B82E24D3F47}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C2447F0B-733D-4755-A104-5B82E24D3F47}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C2447F0B-733D-4755-A104-5B82E24D3F47}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4200B289-ED2B-4C6F-AFDF-EC91FB3837B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4200B289-ED2B-4C6F-AFDF-EC91FB3837B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4200B289-ED2B-4C6F-AFDF-EC91FB3837B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4200B289-ED2B-4C6F-AFDF-EC91FB3837B3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.7.0-3.final" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.7.0-3.final" />
|
||||||
|
60
cmc/Program.cs
Normal file
60
cmc/Program.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using Parser;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Mono.Options;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace cmc
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static int Main(string[] args)
|
||||||
|
{
|
||||||
|
var referencePaths = new List<string>();
|
||||||
|
var outputPath = (string?)null;
|
||||||
|
var moduleName = (string?)null;
|
||||||
|
var helpRequested = false;
|
||||||
|
var sourcePaths = new List<string>();
|
||||||
|
var options = new OptionSet
|
||||||
|
{
|
||||||
|
"usage: cmc <source-paths> [options]",
|
||||||
|
{ "r=", "The {path} of an assembly to reference", v => referencePaths.Add(v) },
|
||||||
|
{ "o=", "The output {path} of the assembly to create", v => outputPath = v },
|
||||||
|
{ "m=", "The {name} of the module", v => moduleName = v },
|
||||||
|
{ "?|h|help", "Prints help", v => helpRequested = true },
|
||||||
|
{ "<>", v => sourcePaths.Add(v) }
|
||||||
|
};
|
||||||
|
|
||||||
|
options.Parse(args);
|
||||||
|
if (helpRequested)
|
||||||
|
{
|
||||||
|
options.WriteOptionDescriptions(Console.Out);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourcePaths.Count > 1)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Cannot compile more than one file.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputPath == null)
|
||||||
|
{
|
||||||
|
outputPath = Path.ChangeExtension(sourcePaths[0], ".exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleName == null)
|
||||||
|
{
|
||||||
|
moduleName = Path.GetFileNameWithoutExtension(outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var sourcePath = sourcePaths[0];
|
||||||
|
var text = File.ReadAllText(sourcePath);
|
||||||
|
var tree = SyntaxTree.Parse(text);
|
||||||
|
var compilation = Compilation.Create(tree);
|
||||||
|
compilation.Emit(referencePaths.ToArray(), outputPath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
cmc/cmc.csproj
Normal file
18
cmc/cmc.csproj
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Parser\Parser.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Mono.Options" Version="6.6.0.161" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -4,7 +4,6 @@ using System.IO;
|
|||||||
|
|
||||||
namespace cmi
|
namespace cmi
|
||||||
{
|
{
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
|
@ -27,7 +27,7 @@ namespace cmi
|
|||||||
var child = children[index];
|
var child = children[index];
|
||||||
if (child.IsNode)
|
if (child.IsNode)
|
||||||
{
|
{
|
||||||
RenderNode(child.AsNode(), indent, index == last);
|
RenderNode(child.AsNode()!, indent, index == last);
|
||||||
}
|
}
|
||||||
else if (child.IsToken)
|
else if (child.IsToken)
|
||||||
{
|
{
|
||||||
|
7
examples/Directory.Build.props
Normal file
7
examples/Directory.Build.props
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<Project>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<DefaultLanguageSourceExtension>.m</DefaultLanguageSourceExtension>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
18
examples/Directory.Build.targets
Normal file
18
examples/Directory.Build.targets
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<Project>
|
||||||
|
|
||||||
|
<Target Name="CreateManifestResourceNames" />
|
||||||
|
|
||||||
|
<Target Name="CoreCompile" DependsOnTargets="$(CoreCompileDependsOn)">
|
||||||
|
<ItemGroup>
|
||||||
|
<ReferencePath Remove="@(ReferencePath)"
|
||||||
|
Condition="'%(FileName)' != 'System.Console' AND
|
||||||
|
'%(FileName)' != 'System.Collections' AND
|
||||||
|
'%(FileName)' != 'System.Runtime'" />
|
||||||
|
<ReferencePath Include="$(MSBuildThisFileDirectory)\..\Parser\bin\Debug\net5.0\Parser.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Message Importance="high" Text="ReferencePath: @(ReferencePath)" />
|
||||||
|
<Exec Command="dotnet run --project "$(MSBuildThisFileDirectory)\..\cmc\cmc.csproj" -- @(Compile->'"%(Identity)"', ' ') /o "@(IntermediateAssembly)" @(ReferencePath->'/r "%(Identity)"', ' ')"
|
||||||
|
WorkingDirectory="$(MSBuildProjectDirectory)" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
@ -1,11 +1,31 @@
|
|||||||
x = 2;
|
x = 2;
|
||||||
f(x);
|
f(x);
|
||||||
|
x = 5;
|
||||||
f(x);
|
f(x);
|
||||||
|
x = 3;
|
||||||
|
f(x);
|
||||||
|
|
||||||
|
% i = 1;
|
||||||
|
% while i <= 10
|
||||||
|
% disp(i);
|
||||||
|
% i = i + 1;
|
||||||
|
% end
|
||||||
|
|
||||||
|
for i = 1:10
|
||||||
|
disp(i);
|
||||||
|
end
|
||||||
|
|
||||||
function f(x)
|
function f(x)
|
||||||
disp('X was');
|
disp('X was');
|
||||||
disp(x);
|
disp(x);
|
||||||
|
if x > 3
|
||||||
|
disp('greater than 3!');
|
||||||
|
elseif x < 3
|
||||||
|
disp('less than 3!');
|
||||||
|
else
|
||||||
|
disp('exactly 3!');
|
||||||
|
end
|
||||||
x = x + 1;
|
x = x + 1;
|
||||||
disp('X is')
|
disp('X + 1 is');
|
||||||
disp(x);
|
disp(x);
|
||||||
end
|
end
|
12
examples/helloworld/helloworld.cmproj
Normal file
12
examples/helloworld/helloworld.cmproj
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Parser\Parser.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
x
Reference in New Issue
Block a user