Merge pull request #6 from mahalex/more-evaluate

More evaluate
This commit is contained in:
Alexander Luzgarev 2022-04-21 09:14:36 -07:00 committed by GitHub
commit e11476f614
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 2616 additions and 348 deletions

View File

@ -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" />

View File

@ -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>();
} }
} }
} }

View File

@ -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">

View File

@ -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 });

View File

@ -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)

View File

@ -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);
} }
} }
} }

View File

@ -25,5 +25,7 @@
Tilde, Tilde,
Caret, Caret,
DotCaret, DotCaret,
LessInt,
PlusInt,
} }
} }

View File

@ -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}.");
} }
} }
} }

View File

@ -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,
} }
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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);
} }
} }
} }

View 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;
}
}
}

View 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;
}
}
}

View 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; }
}
}

View 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; }
}
}

View 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; }
}
}

View File

@ -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
View 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}'.");
}
}
}
}

View 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; }
}
}

View File

@ -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;
} }

View File

@ -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.");
}
} }
} }

View File

@ -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();
} }
} }

View File

@ -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()

View File

@ -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);
} }

View File

@ -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)

View File

@ -58,5 +58,7 @@ namespace Parser.Internal
{ {
return new SyntaxList(_elements, diagnostics); return new SyntaxList(_elements, diagnostics);
} }
public int Length => _elements.Length;
} }
} }

View File

@ -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;
} }
} }

View File

@ -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
} }
; ;

View File

@ -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)

View File

@ -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)
{ {

View File

@ -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;
} }
} }

View File

@ -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);
} }
} }
} }

View File

@ -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();

View 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()}"),
};
}
}
}

View File

@ -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;
}
} }
} }

View 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);
}
}
}

View File

@ -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);

View File

@ -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>

View File

@ -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
View 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();
}
}
}
}
}

View File

@ -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)

View File

@ -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);
} }

View File

@ -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);
} }
} }
} }

View 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();
}
}
}

View File

@ -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);

View File

@ -15,5 +15,10 @@
{ {
DefaultVisit(list); DefaultVisit(list);
} }
public virtual void VisitRoot(RootSyntaxNode node)
{
DefaultVisit(node);
}
} }
} }

View File

@ -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".

View File

@ -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>

View File

@ -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;
} }

View File

@ -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" />

View File

@ -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

View File

@ -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
View 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
View 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>

View File

@ -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)

View File

@ -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)
{ {

View File

@ -0,0 +1,7 @@
<Project>
<PropertyGroup>
<DefaultLanguageSourceExtension>.m</DefaultLanguageSourceExtension>
</PropertyGroup>
</Project>

View 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 &quot;$(MSBuildThisFileDirectory)\..\cmc\cmc.csproj&quot; -- @(Compile->'&quot;%(Identity)&quot;', ' ') /o &quot;@(IntermediateAssembly)&quot; @(ReferencePath->'/r &quot;%(Identity)&quot;', ' ')"
WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
</Project>

View File

@ -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

View 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>