Implement lowering
This commit is contained in:
parent
652bd92f01
commit
7f0889f0d4
@ -169,7 +169,7 @@ namespace ConsoleDemo
|
|||||||
public override void VisitFile(FileSyntaxNode node)
|
public override void VisitFile(FileSyntaxNode node)
|
||||||
{
|
{
|
||||||
_methodAssignments = new MethodAssignments();
|
_methodAssignments = new MethodAssignments();
|
||||||
foreach (var nodeOrToken in node.StatementList)
|
foreach (var nodeOrToken in node.Body.Statements)
|
||||||
{
|
{
|
||||||
if (nodeOrToken.IsToken)
|
if (nodeOrToken.IsToken)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@ namespace ProjectConsole
|
|||||||
{
|
{
|
||||||
public override void VisitFile(FileSyntaxNode node)
|
public override void VisitFile(FileSyntaxNode node)
|
||||||
{
|
{
|
||||||
Visit(node.StatementList);
|
Visit(node.Body.Statements);
|
||||||
OutputKeyword(node.EndOfFile);
|
OutputKeyword(node.EndOfFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ namespace ConsoleDemo
|
|||||||
public override void VisitFile(FileSyntaxNode node)
|
public override void VisitFile(FileSyntaxNode node)
|
||||||
{
|
{
|
||||||
_methodAssignments = new MethodAssignments();
|
_methodAssignments = new MethodAssignments();
|
||||||
foreach (var nodeOrToken in node.StatementList)
|
foreach (var nodeOrToken in node.Body.Statements)
|
||||||
{
|
{
|
||||||
if (nodeOrToken.IsToken)
|
if (nodeOrToken.IsToken)
|
||||||
{
|
{
|
||||||
|
@ -75,7 +75,7 @@ namespace MApplication
|
|||||||
|
|
||||||
public override void VisitFile(FileSyntaxNode node)
|
public override void VisitFile(FileSyntaxNode node)
|
||||||
{
|
{
|
||||||
Visit(node.StatementList);
|
Visit(node.Body.Statements);
|
||||||
AddToken(node.EndOfFile, _scheme.Keyword);
|
AddToken(node.EndOfFile, _scheme.Keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ namespace Parser.Tests
|
|||||||
var text = "a = b";
|
var text = "a = b";
|
||||||
var sut = GetSut(text);
|
var sut = GetSut(text);
|
||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var assignment = actual.Root.StatementList[0].AsNode();
|
var assignment = actual.Root.Body.Statements[0].AsNode();
|
||||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||||
if (assignment is null)
|
if (assignment is null)
|
||||||
{
|
{
|
||||||
@ -35,7 +35,7 @@ namespace Parser.Tests
|
|||||||
var text = "2 + 3";
|
var text = "2 + 3";
|
||||||
var sut = GetSut(text);
|
var sut = GetSut(text);
|
||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var statement = actual.Root.StatementList[0].AsNode();
|
var statement = actual.Root.Body.Statements[0].AsNode();
|
||||||
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
||||||
if (statement is null)
|
if (statement is null)
|
||||||
{
|
{
|
||||||
@ -51,7 +51,7 @@ namespace Parser.Tests
|
|||||||
var text = "a = ";
|
var text = "a = ";
|
||||||
var sut = GetSut(text);
|
var sut = GetSut(text);
|
||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var assignment = actual.Root.StatementList[0].AsNode();
|
var assignment = actual.Root.Body.Statements[0].AsNode();
|
||||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||||
if (assignment is null)
|
if (assignment is null)
|
||||||
{
|
{
|
||||||
@ -77,7 +77,7 @@ namespace Parser.Tests
|
|||||||
var text = "2 + 3";
|
var text = "2 + 3";
|
||||||
var sut = GetSut(text);
|
var sut = GetSut(text);
|
||||||
var actual = sut.Parse();
|
var actual = sut.Parse();
|
||||||
var statement = actual.Root.StatementList[0].AsNode() as ExpressionStatementSyntaxNode;
|
var statement = actual.Root.Body.Statements[0].AsNode() as ExpressionStatementSyntaxNode;
|
||||||
var expression = statement!.Expression as BinaryOperationExpressionSyntaxNode;
|
var expression = statement!.Expression as BinaryOperationExpressionSyntaxNode;
|
||||||
var lhs = expression!.Lhs;
|
var lhs = expression!.Lhs;
|
||||||
var operation = expression.Operation;
|
var operation = expression.Operation;
|
||||||
|
@ -1,24 +1,39 @@
|
|||||||
using Parser.Internal;
|
using Parser.Internal;
|
||||||
|
using Parser.Lowering;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
using static Parser.Binding.BoundNodeFactory;
|
||||||
|
|
||||||
namespace Parser.Binding
|
namespace Parser.Binding
|
||||||
{
|
{
|
||||||
public class Binder
|
public class Binder
|
||||||
{
|
{
|
||||||
private readonly DiagnosticsBag _diagnostics = new DiagnosticsBag();
|
private readonly DiagnosticsBag _diagnostics = new DiagnosticsBag();
|
||||||
|
|
||||||
|
public static BoundProgram BindProgram(SyntaxTree syntaxTree)
|
||||||
|
{
|
||||||
|
var binder = new Binder();
|
||||||
|
var boundRoot = binder.BindRoot(syntaxTree.NullRoot);
|
||||||
|
var loweredStatement = Lowerer.Lower(boundRoot.File.Body);
|
||||||
|
var newRoot = Root(
|
||||||
|
boundRoot.Syntax,
|
||||||
|
File(boundRoot.File.Syntax, loweredStatement));
|
||||||
|
return new BoundProgram(newRoot, binder._diagnostics.ToImmutableArray());
|
||||||
|
}
|
||||||
|
|
||||||
private BoundRoot BindRoot(RootSyntaxNode node)
|
private BoundRoot BindRoot(RootSyntaxNode node)
|
||||||
{
|
{
|
||||||
var boundFile = BindFile(node.File);
|
var boundFile = BindFile(node.File);
|
||||||
return new BoundRoot(node, boundFile);
|
return Root(node, boundFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundFile BindFile(FileSyntaxNode node)
|
private BoundFile BindFile(FileSyntaxNode node)
|
||||||
{
|
{
|
||||||
var statements = BindStatementList(node.StatementList);
|
var body = BindBlockStatement(node.Body);
|
||||||
return new BoundFile(node, statements);
|
return File(node, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundStatement BindStatement(StatementSyntaxNode node)
|
private BoundStatement BindStatement(StatementSyntaxNode node)
|
||||||
@ -27,6 +42,8 @@ namespace Parser.Binding
|
|||||||
{
|
{
|
||||||
TokenKind.AbstractMethodDeclaration =>
|
TokenKind.AbstractMethodDeclaration =>
|
||||||
BindAbstractMethodDeclaration((AbstractMethodDeclarationSyntaxNode)node),
|
BindAbstractMethodDeclaration((AbstractMethodDeclarationSyntaxNode)node),
|
||||||
|
TokenKind.BlockStatement =>
|
||||||
|
BindBlockStatement((BlockStatementSyntaxNode)node),
|
||||||
TokenKind.ClassDeclaration =>
|
TokenKind.ClassDeclaration =>
|
||||||
BindClassDeclaration((ClassDeclarationSyntaxNode)node),
|
BindClassDeclaration((ClassDeclarationSyntaxNode)node),
|
||||||
TokenKind.ConcreteMethodDeclaration =>
|
TokenKind.ConcreteMethodDeclaration =>
|
||||||
@ -86,32 +103,27 @@ namespace Parser.Binding
|
|||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
return new BoundIfStatement(node, condition, body, builder.ToImmutable(), maybeElseClause);
|
return IfStatement(node, condition, body, builder.ToImmutable(), maybeElseClause);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundElseClause BindElseClause(ElseClause node)
|
private BoundStatement BindElseClause(ElseClause node)
|
||||||
{
|
{
|
||||||
var body = BindStatement(node.Body);
|
return BindStatement(node.Body);
|
||||||
return new BoundElseClause(node, body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundBlockStatement BindBlockStatement(BlockStatementSyntaxNode node)
|
private BoundBlockStatement BindBlockStatement(BlockStatementSyntaxNode node)
|
||||||
{
|
{
|
||||||
var boundStatements = BindStatementList(node.Statements);
|
var boundStatements = BindStatementList(node.Statements);
|
||||||
return new BoundBlockStatement(node, boundStatements);
|
return Block(node, boundStatements.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImmutableArray<BoundStatement> BindStatementList(SyntaxNodeOrTokenList list)
|
private IEnumerable<BoundStatement> BindStatementList(SyntaxNodeOrTokenList list)
|
||||||
{
|
{
|
||||||
var builder = ImmutableArray.CreateBuilder<BoundStatement>();
|
|
||||||
var statements = list.Where(s => s.IsNode).Select(s => (StatementSyntaxNode)s.AsNode()!);
|
var statements = list.Where(s => s.IsNode).Select(s => (StatementSyntaxNode)s.AsNode()!);
|
||||||
foreach (var statement in statements)
|
foreach (var statement in statements)
|
||||||
{
|
{
|
||||||
var boundStatement = BindStatement(statement);
|
yield return BindStatement(statement);
|
||||||
builder.Add(boundStatement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.ToImmutable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImmutableArray<BoundExpression> BindExpressionList(SyntaxNodeOrTokenList list)
|
private ImmutableArray<BoundExpression> BindExpressionList(SyntaxNodeOrTokenList list)
|
||||||
@ -131,7 +143,7 @@ namespace Parser.Binding
|
|||||||
{
|
{
|
||||||
var condition = BindExpression(node.Condition);
|
var condition = BindExpression(node.Condition);
|
||||||
var body = BindStatement(node.Body);
|
var body = BindStatement(node.Body);
|
||||||
return new BoundElseifClause(node, condition, body);
|
return ElseifClause(node, condition, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundFunctionDeclaration BindFunctionDeclaration(FunctionDeclarationSyntaxNode node)
|
private BoundFunctionDeclaration BindFunctionDeclaration(FunctionDeclarationSyntaxNode node)
|
||||||
@ -147,7 +159,7 @@ namespace Parser.Binding
|
|||||||
private BoundExpressionStatement BindExpressionStatement(ExpressionStatementSyntaxNode node)
|
private BoundExpressionStatement BindExpressionStatement(ExpressionStatementSyntaxNode node)
|
||||||
{
|
{
|
||||||
var expression = BindExpression(node.Expression);
|
var expression = BindExpression(node.Expression);
|
||||||
return new BoundExpressionStatement(node, expression);
|
return ExpressionStatement(node, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundExpression BindExpression(ExpressionSyntaxNode node)
|
private BoundExpression BindExpression(ExpressionSyntaxNode node)
|
||||||
@ -212,21 +224,14 @@ namespace Parser.Binding
|
|||||||
{
|
{
|
||||||
var left = BindExpression(node.Lhs);
|
var left = BindExpression(node.Lhs);
|
||||||
var right = BindExpression(node.Rhs);
|
var right = BindExpression(node.Rhs);
|
||||||
return new BoundAssignmentExpression(node, left, right);
|
return Assignment(node, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
var op = BindBinaryOperator(node.Operation);
|
return BinaryOperation(node, left, node.Operation.Kind, right);
|
||||||
return new BoundBinaryOperationExpression(node, left, op, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
private BoundBinaryOperator BindBinaryOperator(SyntaxToken token)
|
|
||||||
{
|
|
||||||
return BoundBinaryOperator.GetOperator(token.Kind)
|
|
||||||
?? throw new Exception($"Unexpected binary operator kind {token.Kind}.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundCellArrayElementAccessExpression BindCellArrayElementAccessExpression(CellArrayElementAccessExpressionSyntaxNode node)
|
private BoundCellArrayElementAccessExpression BindCellArrayElementAccessExpression(CellArrayElementAccessExpressionSyntaxNode node)
|
||||||
@ -268,7 +273,7 @@ namespace Parser.Binding
|
|||||||
{
|
{
|
||||||
var name = BindExpression(node.FunctionName);
|
var name = BindExpression(node.FunctionName);
|
||||||
var arguments = BindExpressionList(node.Nodes);
|
var arguments = BindExpressionList(node.Nodes);
|
||||||
return new BoundFunctionCallExpression(node, name, arguments);
|
return FunctionCall(node, name, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundIdentifierNameExpression BindIdentifierNameExpression(IdentifierNameExpressionSyntaxNode node)
|
private BoundIdentifierNameExpression BindIdentifierNameExpression(IdentifierNameExpressionSyntaxNode node)
|
||||||
@ -299,27 +304,27 @@ 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 new BoundNumberLiteralExpression(node, value);
|
return NumberLiteral(node, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundParenthesizedExpression BindParenthesizedExpression(ParenthesizedExpressionSyntaxNode node)
|
private BoundExpression BindParenthesizedExpression(ParenthesizedExpressionSyntaxNode node)
|
||||||
{
|
{
|
||||||
var expression = BindExpression(node.Expression);
|
return BindExpression(node.Expression);
|
||||||
return new BoundParenthesizedExpression(node, expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundStringLiteralExpression BindStringLiteralExpression(StringLiteralExpressionSyntaxNode node)
|
private BoundStringLiteralExpression BindStringLiteralExpression(StringLiteralExpressionSyntaxNode node)
|
||||||
{
|
{
|
||||||
var value = (string)node.StringToken.Value!;
|
var value = (string)node.StringToken.Value!;
|
||||||
return new BoundStringLiteralExpression(node, value);
|
return StringLiteral(node, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundUnaryPrefixOperationExpression BindUnaryPrefixOperationExpression(UnaryPrefixOperationExpressionSyntaxNode node)
|
private BoundUnaryOperationExpression BindUnaryPrefixOperationExpression(UnaryPrefixOperationExpressionSyntaxNode node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var operand = BindExpression(node.Operand);
|
||||||
|
return UnaryOperation(node, node.Operation.Kind, operand);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundUnaryPostfixOperationExpression BindUnaryPostfixOperationExpression(UnaryPostfixOperationExpressionSyntaxNode node)
|
private BoundUnaryOperationExpression BindUnaryPostfixOperationExpression(UnaryPostfixOperationExpressionSyntaxNode node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
@ -348,12 +353,5 @@ namespace Parser.Binding
|
|||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BoundProgram BindProgram(SyntaxTree syntaxTree)
|
|
||||||
{
|
|
||||||
var binder = new Binder();
|
|
||||||
var boundRoot = binder.BindRoot(syntaxTree.NullRoot);
|
|
||||||
return new BoundProgram(boundRoot, binder._diagnostics.ToImmutableArray());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
Parser/Binding/BoundLabel.cs
Normal file
17
Parser/Binding/BoundLabel.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace Parser.Binding
|
||||||
|
{
|
||||||
|
public class BoundLabel
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public BoundLabel(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
170
Parser/Binding/BoundNodeFactory.cs
Normal file
170
Parser/Binding/BoundNodeFactory.cs
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Parser.Binding
|
||||||
|
{
|
||||||
|
public static class BoundNodeFactory
|
||||||
|
{
|
||||||
|
public static BoundRoot Root(SyntaxNode syntax, BoundFile file)
|
||||||
|
{
|
||||||
|
return new BoundRoot(syntax, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundFile File(SyntaxNode syntax, BoundStatement body)
|
||||||
|
{
|
||||||
|
return new BoundFile(syntax, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundBlockStatement Block(SyntaxNode syntax, params BoundStatement[] statements)
|
||||||
|
{
|
||||||
|
return new BoundBlockStatement(syntax, statements.ToImmutableArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundBlockStatement Block(SyntaxNode syntax, ImmutableArray<BoundStatement> statements)
|
||||||
|
{
|
||||||
|
return new BoundBlockStatement(syntax, statements);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundExpressionStatement ExpressionStatement(SyntaxNode syntax, BoundExpression expression)
|
||||||
|
{
|
||||||
|
return new BoundExpressionStatement(syntax, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundIfStatement IfStatement(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression condition,
|
||||||
|
BoundStatement body,
|
||||||
|
ImmutableArray<BoundElseifClause> elseifClauses,
|
||||||
|
BoundStatement? elseClause)
|
||||||
|
{
|
||||||
|
return new BoundIfStatement(syntax, condition, body, elseifClauses, elseClause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundLabelStatement LabelStatement(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundLabel label)
|
||||||
|
{
|
||||||
|
return new BoundLabelStatement(syntax, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundAssignmentExpression Assignment(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression left,
|
||||||
|
BoundExpression right)
|
||||||
|
{
|
||||||
|
return new BoundAssignmentExpression(syntax, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundBinaryOperationExpression BinaryOperation(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression left,
|
||||||
|
TokenKind kind,
|
||||||
|
BoundExpression right)
|
||||||
|
{
|
||||||
|
var op = BindBinaryOperator(kind);
|
||||||
|
return new BoundBinaryOperationExpression(syntax, left, op, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundConditionalGotoStatement ConditionalGoto(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression condition,
|
||||||
|
BoundLabel label,
|
||||||
|
bool gotoIfTrue)
|
||||||
|
{
|
||||||
|
return new BoundConditionalGotoStatement(
|
||||||
|
syntax,
|
||||||
|
condition,
|
||||||
|
label,
|
||||||
|
gotoIfTrue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundConditionalGotoStatement GotoIfTrue(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression condition,
|
||||||
|
BoundLabel label)
|
||||||
|
{
|
||||||
|
return new BoundConditionalGotoStatement(
|
||||||
|
syntax,
|
||||||
|
condition,
|
||||||
|
label,
|
||||||
|
gotoIfTrue: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundConditionalGotoStatement GotoIfFalse(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression condition,
|
||||||
|
BoundLabel label)
|
||||||
|
{
|
||||||
|
return new BoundConditionalGotoStatement(
|
||||||
|
syntax,
|
||||||
|
condition,
|
||||||
|
label,
|
||||||
|
gotoIfTrue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundFunctionCallExpression FunctionCall(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression name,
|
||||||
|
ImmutableArray<BoundExpression> arguments)
|
||||||
|
{
|
||||||
|
return new BoundFunctionCallExpression(syntax, name, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundGotoStatement Goto(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundLabel label)
|
||||||
|
{
|
||||||
|
return new BoundGotoStatement(syntax, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundIdentifierNameExpression Identifier(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
string name)
|
||||||
|
{
|
||||||
|
return new BoundIdentifierNameExpression(syntax, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundNumberLiteralExpression NumberLiteral(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
double value)
|
||||||
|
{
|
||||||
|
return new BoundNumberLiteralExpression(syntax, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundStringLiteralExpression StringLiteral(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
string value)
|
||||||
|
{
|
||||||
|
return new BoundStringLiteralExpression(syntax, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundElseifClause ElseifClause(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
BoundExpression condition,
|
||||||
|
BoundStatement body)
|
||||||
|
{
|
||||||
|
return new BoundElseifClause(syntax, condition, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundUnaryOperationExpression UnaryOperation(
|
||||||
|
SyntaxNode syntax,
|
||||||
|
TokenKind kind,
|
||||||
|
BoundExpression operand)
|
||||||
|
{
|
||||||
|
var op = BindUnaryOperator(kind);
|
||||||
|
return new BoundUnaryOperationExpression(syntax, op, operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundUnaryOperator BindUnaryOperator(TokenKind kind)
|
||||||
|
{
|
||||||
|
return BoundUnaryOperator.GetOperator(kind)
|
||||||
|
?? throw new Exception($"Unexpected unary operator kind {kind}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundBinaryOperator BindBinaryOperator(TokenKind kind)
|
||||||
|
{
|
||||||
|
return BoundBinaryOperator.GetOperator(kind)
|
||||||
|
?? throw new Exception($"Unexpected binary operator kind {kind}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,11 +11,14 @@
|
|||||||
BlockStatement,
|
BlockStatement,
|
||||||
ClassDeclaration,
|
ClassDeclaration,
|
||||||
ConcreteMethodDeclaration,
|
ConcreteMethodDeclaration,
|
||||||
|
ConditionalGotoStatement,
|
||||||
EmptyStatement,
|
EmptyStatement,
|
||||||
ExpressionStatement,
|
ExpressionStatement,
|
||||||
ForStatement,
|
ForStatement,
|
||||||
FunctionDeclaration,
|
FunctionDeclaration,
|
||||||
|
GotoStatement,
|
||||||
IfStatement,
|
IfStatement,
|
||||||
|
LabelStatement,
|
||||||
SwitchStatement,
|
SwitchStatement,
|
||||||
TryCatchStatement,
|
TryCatchStatement,
|
||||||
WhileStatement,
|
WhileStatement,
|
||||||
@ -41,8 +44,7 @@
|
|||||||
NumberLiteralExpression,
|
NumberLiteralExpression,
|
||||||
ParenthesizedExpression,
|
ParenthesizedExpression,
|
||||||
StringLiteralExpression,
|
StringLiteralExpression,
|
||||||
UnaryPrefixOperationExpression,
|
UnaryOperationExpression,
|
||||||
UnaryPostfixOperationExpression,
|
|
||||||
UnquotedStringLiteralExpression,
|
UnquotedStringLiteralExpression,
|
||||||
|
|
||||||
// Parts
|
// Parts
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Immutable;
|
||||||
using System.Collections.Immutable;
|
|
||||||
|
|
||||||
namespace Parser.Binding
|
namespace Parser.Binding
|
||||||
{
|
{
|
||||||
@ -18,13 +17,13 @@ namespace Parser.Binding
|
|||||||
|
|
||||||
public class BoundFile : BoundNode
|
public class BoundFile : BoundNode
|
||||||
{
|
{
|
||||||
public BoundFile(SyntaxNode syntax, ImmutableArray<BoundStatement> statements)
|
public BoundFile(SyntaxNode syntax, BoundStatement body)
|
||||||
: base(syntax)
|
: base(syntax)
|
||||||
{
|
{
|
||||||
Statements = statements;
|
Body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableArray<BoundStatement> Statements { get; }
|
public BoundStatement Body { get; }
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.File;
|
public override BoundNodeKind Kind => BoundNodeKind.File;
|
||||||
}
|
}
|
||||||
@ -88,6 +87,25 @@ namespace Parser.Binding
|
|||||||
public override BoundNodeKind Kind => BoundNodeKind.ConcreteMethodDeclaration;
|
public override BoundNodeKind Kind => BoundNodeKind.ConcreteMethodDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class BoundConditionalGotoStatement : BoundStatement
|
||||||
|
{
|
||||||
|
public BoundConditionalGotoStatement(SyntaxNode syntax, BoundExpression condition, BoundLabel label, bool gotoIfTrue = true)
|
||||||
|
: base(syntax)
|
||||||
|
{
|
||||||
|
Condition = condition;
|
||||||
|
Label = label;
|
||||||
|
GotoIfTrue = gotoIfTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundExpression Condition { get; }
|
||||||
|
|
||||||
|
public BoundLabel Label { get; }
|
||||||
|
|
||||||
|
public bool GotoIfTrue { get; }
|
||||||
|
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.ConditionalGotoStatement;
|
||||||
|
}
|
||||||
|
|
||||||
public class BoundEmptyStatement : BoundStatement
|
public class BoundEmptyStatement : BoundStatement
|
||||||
{
|
{
|
||||||
public BoundEmptyStatement(SyntaxNode syntax)
|
public BoundEmptyStatement(SyntaxNode syntax)
|
||||||
@ -131,9 +149,22 @@ namespace Parser.Binding
|
|||||||
public override BoundNodeKind Kind => BoundNodeKind.FunctionDeclaration;
|
public override BoundNodeKind Kind => BoundNodeKind.FunctionDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class BoundGotoStatement : BoundStatement
|
||||||
|
{
|
||||||
|
public BoundGotoStatement(SyntaxNode syntax, BoundLabel label)
|
||||||
|
: base(syntax)
|
||||||
|
{
|
||||||
|
Label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundLabel Label { get; }
|
||||||
|
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.GotoStatement;
|
||||||
|
}
|
||||||
|
|
||||||
public class BoundIfStatement : BoundStatement
|
public class BoundIfStatement : BoundStatement
|
||||||
{
|
{
|
||||||
public BoundIfStatement(SyntaxNode syntax, BoundExpression condition, BoundStatement body, ImmutableArray<BoundElseifClause> elseifClauses, BoundElseClause? elseClause)
|
public BoundIfStatement(SyntaxNode syntax, BoundExpression condition, BoundStatement body, ImmutableArray<BoundElseifClause> elseifClauses, BoundStatement? elseClause)
|
||||||
: base(syntax)
|
: base(syntax)
|
||||||
{
|
{
|
||||||
Condition = condition;
|
Condition = condition;
|
||||||
@ -145,11 +176,24 @@ namespace Parser.Binding
|
|||||||
public BoundExpression Condition { get; }
|
public BoundExpression Condition { get; }
|
||||||
public BoundStatement Body { get; }
|
public BoundStatement Body { get; }
|
||||||
public ImmutableArray<BoundElseifClause> ElseifClauses { get; }
|
public ImmutableArray<BoundElseifClause> ElseifClauses { get; }
|
||||||
public BoundElseClause? ElseClause { get; }
|
public BoundStatement? ElseClause { get; }
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.IfStatement;
|
public override BoundNodeKind Kind => BoundNodeKind.IfStatement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class BoundLabelStatement : BoundStatement
|
||||||
|
{
|
||||||
|
public BoundLabelStatement(SyntaxNode syntax, BoundLabel label)
|
||||||
|
: base(syntax)
|
||||||
|
{
|
||||||
|
Label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoundLabel Label { get; }
|
||||||
|
|
||||||
|
public override BoundNodeKind Kind => BoundNodeKind.LabelStatement;
|
||||||
|
}
|
||||||
|
|
||||||
public class BoundSwitchStatement : BoundStatement
|
public class BoundSwitchStatement : BoundStatement
|
||||||
{
|
{
|
||||||
public BoundSwitchStatement(SyntaxNode syntax)
|
public BoundSwitchStatement(SyntaxNode syntax)
|
||||||
@ -378,19 +422,6 @@ namespace Parser.Binding
|
|||||||
public override BoundNodeKind Kind => BoundNodeKind.NumberLiteralExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.NumberLiteralExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundParenthesizedExpression : BoundExpression
|
|
||||||
{
|
|
||||||
public BoundParenthesizedExpression(SyntaxNode syntax, BoundExpression expression)
|
|
||||||
: base(syntax)
|
|
||||||
{
|
|
||||||
Expression = expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.ParenthesizedExpression;
|
|
||||||
|
|
||||||
public BoundExpression Expression { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BoundStringLiteralExpression : BoundExpression
|
public class BoundStringLiteralExpression : BoundExpression
|
||||||
{
|
{
|
||||||
public BoundStringLiteralExpression(SyntaxNode syntax, string value)
|
public BoundStringLiteralExpression(SyntaxNode syntax, string value)
|
||||||
@ -403,24 +434,19 @@ namespace Parser.Binding
|
|||||||
public override BoundNodeKind Kind => BoundNodeKind.StringLiteralExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.StringLiteralExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundUnaryPrefixOperationExpression : BoundExpression
|
public class BoundUnaryOperationExpression : BoundExpression
|
||||||
{
|
{
|
||||||
public BoundUnaryPrefixOperationExpression(SyntaxNode syntax)
|
public BoundUnaryOperationExpression(SyntaxNode syntax, BoundUnaryOperator op, BoundExpression operand)
|
||||||
: base(syntax)
|
: base(syntax)
|
||||||
{
|
{
|
||||||
|
Op = op;
|
||||||
|
Operand = operand;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.UnaryPrefixOperationExpression;
|
public override BoundNodeKind Kind => BoundNodeKind.UnaryOperationExpression;
|
||||||
}
|
|
||||||
|
|
||||||
public class BoundUnaryPostfixOperationExpression : BoundExpression
|
public BoundUnaryOperator Op { get; }
|
||||||
{
|
public BoundExpression Operand { get; }
|
||||||
public BoundUnaryPostfixOperationExpression(SyntaxNode syntax)
|
|
||||||
: base(syntax)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.UnaryPostfixOperationExpression;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundUnquotedStringLiteralExpression : BoundExpression
|
public class BoundUnquotedStringLiteralExpression : BoundExpression
|
||||||
@ -446,16 +472,4 @@ namespace Parser.Binding
|
|||||||
public BoundStatement Body { get; }
|
public BoundStatement Body { get; }
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.ElseIfClause;
|
public override BoundNodeKind Kind => BoundNodeKind.ElseIfClause;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoundElseClause : BoundNode
|
|
||||||
{
|
|
||||||
public BoundElseClause(SyntaxNode syntax, BoundStatement body)
|
|
||||||
: base(syntax)
|
|
||||||
{
|
|
||||||
Body = body;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BoundStatement Body { get; }
|
|
||||||
public override BoundNodeKind Kind => BoundNodeKind.ElseClause;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using static Parser.Binding.BoundNodeFactory;
|
||||||
|
|
||||||
namespace Parser.Binding
|
namespace Parser.Binding
|
||||||
{
|
{
|
||||||
@ -17,6 +18,8 @@ namespace Parser.Binding
|
|||||||
RewriteClassDeclaration((BoundClassDeclaration)node),
|
RewriteClassDeclaration((BoundClassDeclaration)node),
|
||||||
BoundNodeKind.ConcreteMethodDeclaration =>
|
BoundNodeKind.ConcreteMethodDeclaration =>
|
||||||
RewriteConcreteMethodDeclaration((BoundConcreteMethodDeclaration)node),
|
RewriteConcreteMethodDeclaration((BoundConcreteMethodDeclaration)node),
|
||||||
|
BoundNodeKind.ConditionalGotoStatement =>
|
||||||
|
RewriteConditionalGotoStatement((BoundConditionalGotoStatement)node),
|
||||||
BoundNodeKind.EmptyStatement =>
|
BoundNodeKind.EmptyStatement =>
|
||||||
RewriteEmptyStatement((BoundEmptyStatement)node),
|
RewriteEmptyStatement((BoundEmptyStatement)node),
|
||||||
BoundNodeKind.ExpressionStatement =>
|
BoundNodeKind.ExpressionStatement =>
|
||||||
@ -25,8 +28,12 @@ namespace Parser.Binding
|
|||||||
RewriteForStatement((BoundForStatement)node),
|
RewriteForStatement((BoundForStatement)node),
|
||||||
BoundNodeKind.FunctionDeclaration =>
|
BoundNodeKind.FunctionDeclaration =>
|
||||||
RewriteFunctionDeclaration((BoundFunctionDeclaration)node),
|
RewriteFunctionDeclaration((BoundFunctionDeclaration)node),
|
||||||
|
BoundNodeKind.GotoStatement =>
|
||||||
|
RewriteGotoStatement((BoundGotoStatement)node),
|
||||||
BoundNodeKind.IfStatement =>
|
BoundNodeKind.IfStatement =>
|
||||||
RewriteIfStatement((BoundIfStatement)node),
|
RewriteIfStatement((BoundIfStatement)node),
|
||||||
|
BoundNodeKind.LabelStatement =>
|
||||||
|
RewriteLabelStatement((BoundLabelStatement)node),
|
||||||
BoundNodeKind.SwitchStatement =>
|
BoundNodeKind.SwitchStatement =>
|
||||||
RewriteSwitchStatement((BoundSwitchStatement)node),
|
RewriteSwitchStatement((BoundSwitchStatement)node),
|
||||||
BoundNodeKind.TryCatchStatement =>
|
BoundNodeKind.TryCatchStatement =>
|
||||||
@ -38,6 +45,22 @@ namespace Parser.Binding
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual BoundStatement RewriteGotoStatement(BoundGotoStatement node)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual BoundStatement RewriteConditionalGotoStatement(BoundConditionalGotoStatement node)
|
||||||
|
{
|
||||||
|
var condition = RewriteExpression(node.Condition);
|
||||||
|
if (condition == node.Condition)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConditionalGoto(node.Syntax, condition, node.Label, node.GotoIfTrue);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual BoundStatement RewriteWhileStatement(BoundWhileStatement node)
|
public virtual BoundStatement RewriteWhileStatement(BoundWhileStatement node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@ -53,6 +76,11 @@ namespace Parser.Binding
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual BoundStatement RewriteLabelStatement(BoundLabelStatement node)
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual BoundStatement RewriteIfStatement(BoundIfStatement node)
|
public virtual BoundStatement RewriteIfStatement(BoundIfStatement node)
|
||||||
{
|
{
|
||||||
var condition = RewriteExpression(node.Condition);
|
var condition = RewriteExpression(node.Condition);
|
||||||
@ -65,7 +93,7 @@ namespace Parser.Binding
|
|||||||
if (oldClause != newClause && builder is null)
|
if (oldClause != newClause && builder is null)
|
||||||
{
|
{
|
||||||
builder = ImmutableArray.CreateBuilder<BoundElseifClause>(node.ElseifClauses.Length);
|
builder = ImmutableArray.CreateBuilder<BoundElseifClause>(node.ElseifClauses.Length);
|
||||||
for (var j = 0; j < i; i++)
|
for (var j = 0; j < i; j++)
|
||||||
{
|
{
|
||||||
builder.Add(node.ElseifClauses[j]);
|
builder.Add(node.ElseifClauses[j]);
|
||||||
}
|
}
|
||||||
@ -74,11 +102,10 @@ namespace Parser.Binding
|
|||||||
{
|
{
|
||||||
builder.Add(newClause);
|
builder.Add(newClause);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var elseIfClauses = builder is null ? node.ElseifClauses : builder.MoveToImmutable();
|
var elseIfClauses = builder is null ? node.ElseifClauses : builder.MoveToImmutable();
|
||||||
var elseClause = node.ElseClause is null ? null : RewriteElseifClause(node.ElseClause);
|
var elseClause = node.ElseClause is null ? null : RewriteStatement(node.ElseClause);
|
||||||
if (condition == node.Condition &&
|
if (condition == node.Condition &&
|
||||||
body == node.Body &&
|
body == node.Body &&
|
||||||
elseIfClauses == node.ElseifClauses &&
|
elseIfClauses == node.ElseifClauses &&
|
||||||
@ -87,18 +114,7 @@ namespace Parser.Binding
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BoundIfStatement(node.Syntax, condition, body, elseIfClauses, elseClause);
|
return IfStatement(node.Syntax, condition, body, elseIfClauses, elseClause);
|
||||||
}
|
|
||||||
|
|
||||||
public virtual BoundElseClause RewriteElseifClause(BoundElseClause node)
|
|
||||||
{
|
|
||||||
var body = RewriteStatement(node.Body);
|
|
||||||
if (body == node.Body)
|
|
||||||
{
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BoundElseClause(node.Syntax, body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundElseifClause RewriteElseifClause(BoundElseifClause node)
|
public virtual BoundElseifClause RewriteElseifClause(BoundElseifClause node)
|
||||||
@ -110,7 +126,7 @@ namespace Parser.Binding
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BoundElseifClause(node.Syntax, condition, body);
|
return ElseifClause(node.Syntax, condition, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundStatement RewriteFunctionDeclaration(BoundFunctionDeclaration node)
|
public virtual BoundStatement RewriteFunctionDeclaration(BoundFunctionDeclaration node)
|
||||||
@ -131,7 +147,7 @@ namespace Parser.Binding
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BoundExpressionStatement(node.Syntax, expression);
|
return ExpressionStatement(node.Syntax, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundStatement RewriteEmptyStatement(BoundEmptyStatement node)
|
public virtual BoundStatement RewriteEmptyStatement(BoundEmptyStatement node)
|
||||||
@ -159,7 +175,7 @@ namespace Parser.Binding
|
|||||||
if (oldStatement != newStatement && builder is null)
|
if (oldStatement != newStatement && builder is null)
|
||||||
{
|
{
|
||||||
builder = ImmutableArray.CreateBuilder<BoundStatement>(node.Statements.Length);
|
builder = ImmutableArray.CreateBuilder<BoundStatement>(node.Statements.Length);
|
||||||
for (var j = 0; j < i; i++)
|
for (var j = 0; j < i; j++)
|
||||||
{
|
{
|
||||||
builder.Add(node.Statements[j]);
|
builder.Add(node.Statements[j]);
|
||||||
}
|
}
|
||||||
@ -176,7 +192,7 @@ namespace Parser.Binding
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BoundBlockStatement(node.Syntax, builder.MoveToImmutable());
|
return Block(node.Syntax, builder.MoveToImmutable());
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundStatement RewriteAbstractMethodDeclaration(BoundAbstractMethodDeclaration node)
|
public virtual BoundStatement RewriteAbstractMethodDeclaration(BoundAbstractMethodDeclaration node)
|
||||||
@ -222,14 +238,10 @@ namespace Parser.Binding
|
|||||||
RewriteNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
RewriteNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
||||||
BoundNodeKind.NumberLiteralExpression =>
|
BoundNodeKind.NumberLiteralExpression =>
|
||||||
RewriteNumberLiteralExpression((BoundNumberLiteralExpression)node),
|
RewriteNumberLiteralExpression((BoundNumberLiteralExpression)node),
|
||||||
BoundNodeKind.ParenthesizedExpression =>
|
|
||||||
RewriteParenthesizedExpression((BoundParenthesizedExpression)node),
|
|
||||||
BoundNodeKind.StringLiteralExpression =>
|
BoundNodeKind.StringLiteralExpression =>
|
||||||
RewriteStringLiteralExpression((BoundStringLiteralExpression)node),
|
RewriteStringLiteralExpression((BoundStringLiteralExpression)node),
|
||||||
BoundNodeKind.UnaryPrefixOperationExpression =>
|
BoundNodeKind.UnaryOperationExpression =>
|
||||||
RewriteUnaryPrefixOperationExpression((BoundUnaryPrefixOperationExpression)node),
|
RewriteUnaryOperationExpression((BoundUnaryOperationExpression)node),
|
||||||
BoundNodeKind.UnaryPostfixOperationExpression =>
|
|
||||||
RewriteUnaryPostfixOperationExpression((BoundUnaryPostfixOperationExpression)node),
|
|
||||||
BoundNodeKind.UnquotedStringLiteralExpression =>
|
BoundNodeKind.UnquotedStringLiteralExpression =>
|
||||||
RewriteUnquotedStringLiteralExpression((BoundUnquotedStringLiteralExpression)node),
|
RewriteUnquotedStringLiteralExpression((BoundUnquotedStringLiteralExpression)node),
|
||||||
_ =>
|
_ =>
|
||||||
@ -242,14 +254,10 @@ namespace Parser.Binding
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundExpression RewriteUnaryPostfixOperationExpression(BoundUnaryPostfixOperationExpression node)
|
public virtual BoundExpression RewriteUnaryOperationExpression(BoundUnaryOperationExpression node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var operand = RewriteExpression(node.Operand);
|
||||||
}
|
return new BoundUnaryOperationExpression(node.Syntax, node.Op, operand);
|
||||||
|
|
||||||
public virtual BoundExpression RewriteUnaryPrefixOperationExpression(BoundUnaryPrefixOperationExpression node)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundExpression RewriteStringLiteralExpression(BoundStringLiteralExpression node)
|
public virtual BoundExpression RewriteStringLiteralExpression(BoundStringLiteralExpression node)
|
||||||
@ -257,17 +265,6 @@ namespace Parser.Binding
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundExpression RewriteParenthesizedExpression(BoundParenthesizedExpression node)
|
|
||||||
{
|
|
||||||
var expression = RewriteExpression(node.Expression);
|
|
||||||
if (expression == node.Expression)
|
|
||||||
{
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BoundParenthesizedExpression(node.Syntax, expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual BoundExpression RewriteNumberLiteralExpression(BoundNumberLiteralExpression node)
|
public virtual BoundExpression RewriteNumberLiteralExpression(BoundNumberLiteralExpression node)
|
||||||
{
|
{
|
||||||
return node;
|
return node;
|
||||||
@ -309,7 +306,7 @@ namespace Parser.Binding
|
|||||||
if (oldArgument != newArgument && builder is null)
|
if (oldArgument != newArgument && builder is null)
|
||||||
{
|
{
|
||||||
builder = ImmutableArray.CreateBuilder<BoundExpression>(node.Arguments.Length);
|
builder = ImmutableArray.CreateBuilder<BoundExpression>(node.Arguments.Length);
|
||||||
for (var j = 0; j < i; i++)
|
for (var j = 0; j < i; j++)
|
||||||
{
|
{
|
||||||
builder.Add(node.Arguments[j]);
|
builder.Add(node.Arguments[j]);
|
||||||
}
|
}
|
||||||
@ -326,7 +323,7 @@ namespace Parser.Binding
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BoundFunctionCallExpression(node.Syntax, node.Name, builder.MoveToImmutable());
|
return FunctionCall(node.Syntax, node.Name, builder.MoveToImmutable());
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundExpression RewriteEmptyExpression(BoundEmptyExpression node)
|
public virtual BoundExpression RewriteEmptyExpression(BoundEmptyExpression node)
|
||||||
@ -385,7 +382,7 @@ namespace Parser.Binding
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BoundAssignmentExpression(node.Syntax, left, right);
|
return Assignment(node.Syntax, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual BoundExpression RewriteArrayLiteralExpression(BoundArrayLiteralExpression node)
|
public virtual BoundExpression RewriteArrayLiteralExpression(BoundArrayLiteralExpression node)
|
||||||
|
26
Parser/Binding/BoundUnaryOperator.cs
Normal file
26
Parser/Binding/BoundUnaryOperator.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Parser.Binding
|
||||||
|
{
|
||||||
|
public class BoundUnaryOperator
|
||||||
|
{
|
||||||
|
private static BoundUnaryOperator[] _operators =
|
||||||
|
{
|
||||||
|
new BoundUnaryOperator(TokenKind.MinusToken, BoundUnaryOperatorKind.Minus),
|
||||||
|
};
|
||||||
|
|
||||||
|
public BoundUnaryOperator(TokenKind syntaxKind, BoundUnaryOperatorKind kind)
|
||||||
|
{
|
||||||
|
SyntaxKind = syntaxKind;
|
||||||
|
Kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenKind SyntaxKind { get; }
|
||||||
|
public BoundUnaryOperatorKind Kind { get; }
|
||||||
|
|
||||||
|
internal static BoundUnaryOperator? GetOperator(TokenKind kind)
|
||||||
|
{
|
||||||
|
return _operators.FirstOrDefault(op => op.SyntaxKind == kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Parser/Binding/BoundUnaryOperatorKind.cs
Normal file
7
Parser/Binding/BoundUnaryOperatorKind.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Parser.Binding
|
||||||
|
{
|
||||||
|
public enum BoundUnaryOperatorKind
|
||||||
|
{
|
||||||
|
Minus,
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,6 @@ using Parser.Objects;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Parser
|
namespace Parser
|
||||||
{
|
{
|
||||||
@ -33,21 +32,77 @@ namespace Parser
|
|||||||
|
|
||||||
private MObject? EvaluateFile(BoundFile root)
|
private MObject? EvaluateFile(BoundFile root)
|
||||||
{
|
{
|
||||||
MObject? lastResult = null;
|
return EvaluateStatement(root.Body);
|
||||||
foreach (var statement in root.Statements)
|
}
|
||||||
|
|
||||||
|
private MObject? EvaluateBlockStatement(BoundBlockStatement node)
|
||||||
|
{
|
||||||
|
var labelToIndex = new Dictionary<BoundLabel, int>();
|
||||||
|
for (var i = 0; i < node.Statements.Length; i++)
|
||||||
{
|
{
|
||||||
lastResult = EvaluateStatement(statement) ?? lastResult;
|
var statement = node.Statements[i];
|
||||||
|
if (statement.Kind == BoundNodeKind.LabelStatement)
|
||||||
|
{
|
||||||
|
labelToIndex[((BoundLabelStatement)statement).Label] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MObject? lastResult = null;
|
||||||
|
var index = 0;
|
||||||
|
while (index < node.Statements.Length)
|
||||||
|
{
|
||||||
|
var statement = node.Statements[index];
|
||||||
|
switch (statement.Kind)
|
||||||
|
{
|
||||||
|
case BoundNodeKind.GotoStatement:
|
||||||
|
var gs = (BoundGotoStatement)statement;
|
||||||
|
index = labelToIndex[gs.Label];
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.ConditionalGotoStatement:
|
||||||
|
var cgs = (BoundConditionalGotoStatement)statement;
|
||||||
|
var value = EvaluateExpression(cgs.Condition);
|
||||||
|
var truth = IsTruthyValue(value);
|
||||||
|
if ((cgs.GotoIfTrue && truth) ||
|
||||||
|
(!cgs.GotoIfTrue && !truth))
|
||||||
|
{
|
||||||
|
index = labelToIndex[cgs.Label];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BoundNodeKind.LabelStatement:
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lastResult = EvaluateStatement(statement) ?? lastResult;
|
||||||
|
index++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lastResult;
|
return lastResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsTruthyValue(MObject? expression)
|
||||||
|
{
|
||||||
|
if (expression is MLogical { Value: true })
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private MObject? EvaluateStatement(BoundStatement node)
|
private MObject? EvaluateStatement(BoundStatement node)
|
||||||
{
|
{
|
||||||
return node.Kind switch
|
return node.Kind switch
|
||||||
{
|
{
|
||||||
BoundNodeKind.AbstractMethodDeclaration =>
|
BoundNodeKind.AbstractMethodDeclaration =>
|
||||||
EvaluateAbstractMethodDeclaration((BoundAbstractMethodDeclaration)node),
|
EvaluateAbstractMethodDeclaration((BoundAbstractMethodDeclaration)node),
|
||||||
|
BoundNodeKind.BlockStatement =>
|
||||||
|
EvaluateBlockStatement((BoundBlockStatement)node),
|
||||||
BoundNodeKind.ClassDeclaration =>
|
BoundNodeKind.ClassDeclaration =>
|
||||||
EvaluateClassDeclaration((BoundClassDeclaration)node),
|
EvaluateClassDeclaration((BoundClassDeclaration)node),
|
||||||
BoundNodeKind.EmptyStatement =>
|
BoundNodeKind.EmptyStatement =>
|
||||||
@ -165,25 +220,16 @@ namespace Parser
|
|||||||
EvaluateNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
EvaluateNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
||||||
BoundNodeKind.NumberLiteralExpression =>
|
BoundNodeKind.NumberLiteralExpression =>
|
||||||
EvaluateNumberLiteralExpression((BoundNumberLiteralExpression)node),
|
EvaluateNumberLiteralExpression((BoundNumberLiteralExpression)node),
|
||||||
BoundNodeKind.ParenthesizedExpression =>
|
|
||||||
EvaluateParenthesizedExpression((BoundParenthesizedExpression)node),
|
|
||||||
BoundNodeKind.StringLiteralExpression =>
|
BoundNodeKind.StringLiteralExpression =>
|
||||||
EvaluateStringLiteralExpression((BoundStringLiteralExpression)node),
|
EvaluateStringLiteralExpression((BoundStringLiteralExpression)node),
|
||||||
BoundNodeKind.UnaryPrefixOperationExpression =>
|
BoundNodeKind.UnaryOperationExpression =>
|
||||||
EvaluateUnaryPrefixOperationExpression((BoundUnaryPrefixOperationExpression)node),
|
EvaluateUnaryOperationExpression((BoundUnaryOperationExpression)node),
|
||||||
BoundNodeKind.UnaryPostfixOperationExpression =>
|
|
||||||
EvaluateUnaryPostfixOperationExpression((BoundUnaryPostfixOperationExpression)node),
|
|
||||||
BoundNodeKind.UnquotedStringLiteralExpression =>
|
BoundNodeKind.UnquotedStringLiteralExpression =>
|
||||||
EvaluateUnquotedStringLiteralExpression((BoundUnquotedStringLiteralExpression)node),
|
EvaluateUnquotedStringLiteralExpression((BoundUnquotedStringLiteralExpression)node),
|
||||||
_ => throw new NotImplementedException($"Invalid expression kind '{node.Kind}'."),
|
_ => throw new NotImplementedException($"Invalid expression kind '{node.Kind}'."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateParenthesizedExpression(BoundParenthesizedExpression node)
|
|
||||||
{
|
|
||||||
return EvaluateExpression(node.Expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MObject? EvaluateClassInvokation(BoundClassInvokationExpression node)
|
private MObject? EvaluateClassInvokation(BoundClassInvokationExpression node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@ -199,11 +245,6 @@ namespace Parser
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateUnaryPostfixOperationExpression(BoundUnaryPostfixOperationExpression node)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private MObject? EvaluateMemberAccess(BoundMemberAccessExpression node)
|
private MObject? EvaluateMemberAccess(BoundMemberAccessExpression node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@ -338,6 +379,10 @@ namespace Parser
|
|||||||
BoundBinaryOperatorKind.Minus => MOperations.Minus(left, right),
|
BoundBinaryOperatorKind.Minus => MOperations.Minus(left, right),
|
||||||
BoundBinaryOperatorKind.Star => MOperations.Star(left, right),
|
BoundBinaryOperatorKind.Star => MOperations.Star(left, right),
|
||||||
BoundBinaryOperatorKind.Slash => MOperations.Slash(left, right),
|
BoundBinaryOperatorKind.Slash => MOperations.Slash(left, right),
|
||||||
|
BoundBinaryOperatorKind.Greater => MOperations.Greater(left, right),
|
||||||
|
BoundBinaryOperatorKind.GreaterOrEquals => MOperations.GreaterOrEquals(left, right),
|
||||||
|
BoundBinaryOperatorKind.Less => MOperations.Less(left, right),
|
||||||
|
BoundBinaryOperatorKind.LessOrEquals => MOperations.LessOrEquals(left, right),
|
||||||
_ => throw new NotImplementedException($"Binary operation {node.Op.Kind} is not implemented."),
|
_ => throw new NotImplementedException($"Binary operation {node.Op.Kind} is not implemented."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -347,9 +392,19 @@ namespace Parser
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateUnaryPrefixOperationExpression(BoundUnaryPrefixOperationExpression node)
|
private MObject? EvaluateUnaryOperationExpression(BoundUnaryOperationExpression node)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var operand = EvaluateExpression(node.Operand);
|
||||||
|
if (operand is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.Op.Kind switch
|
||||||
|
{
|
||||||
|
BoundUnaryOperatorKind.Minus => MOperations.Minus(operand),
|
||||||
|
_ => throw new NotImplementedException($"Unary operation {node.Op.Kind} is not implemented."),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private MObject? EvaluateEmptyExpression(BoundEmptyExpression node)
|
private MObject? EvaluateEmptyExpression(BoundEmptyExpression node)
|
||||||
|
@ -1220,7 +1220,7 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
public FileSyntaxNode ParseFile()
|
public FileSyntaxNode ParseFile()
|
||||||
{
|
{
|
||||||
var statementList = ParseStatementList();
|
var statementList = ParseBlockStatement();
|
||||||
var endOfFileToken = EatToken();
|
var endOfFileToken = EatToken();
|
||||||
return Factory.FileSyntax(statementList, endOfFileToken);
|
return Factory.FileSyntax(statementList, endOfFileToken);
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
internal partial class SyntaxFactory
|
internal partial class SyntaxFactory
|
||||||
{
|
{
|
||||||
public FileSyntaxNode FileSyntax(SyntaxList statementList, SyntaxToken endOfFile)
|
public FileSyntaxNode FileSyntax(BlockStatementSyntaxNode body, SyntaxToken endOfFile)
|
||||||
{
|
{
|
||||||
return new FileSyntaxNode(statementList, endOfFile);
|
return new FileSyntaxNode(body, endOfFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockStatementSyntaxNode BlockStatementSyntax(SyntaxList statements)
|
public BlockStatementSyntaxNode BlockStatementSyntax(SyntaxList statements)
|
||||||
|
@ -3,22 +3,22 @@ namespace Parser.Internal
|
|||||||
{
|
{
|
||||||
internal class FileSyntaxNode : SyntaxNode
|
internal class FileSyntaxNode : SyntaxNode
|
||||||
{
|
{
|
||||||
internal readonly SyntaxList _statementList;
|
internal readonly BlockStatementSyntaxNode _body;
|
||||||
internal readonly SyntaxToken _endOfFile;
|
internal readonly SyntaxToken _endOfFile;
|
||||||
internal FileSyntaxNode(SyntaxList statementList, SyntaxToken endOfFile): base(TokenKind.File)
|
internal FileSyntaxNode(BlockStatementSyntaxNode body, SyntaxToken endOfFile): base(TokenKind.File)
|
||||||
{
|
{
|
||||||
Slots = 2;
|
Slots = 2;
|
||||||
this.AdjustWidth(statementList);
|
this.AdjustWidth(body);
|
||||||
_statementList = statementList;
|
_body = body;
|
||||||
this.AdjustWidth(endOfFile);
|
this.AdjustWidth(endOfFile);
|
||||||
_endOfFile = endOfFile;
|
_endOfFile = endOfFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal FileSyntaxNode(SyntaxList statementList, 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(statementList);
|
this.AdjustWidth(body);
|
||||||
_statementList = statementList;
|
_body = body;
|
||||||
this.AdjustWidth(endOfFile);
|
this.AdjustWidth(endOfFile);
|
||||||
_endOfFile = endOfFile;
|
_endOfFile = endOfFile;
|
||||||
}
|
}
|
||||||
@ -30,14 +30,14 @@ namespace Parser.Internal
|
|||||||
|
|
||||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||||
{
|
{
|
||||||
return new FileSyntaxNode(_statementList, _endOfFile, diagnostics);
|
return new FileSyntaxNode(_body, _endOfFile, diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override GreenNode? GetSlot(int i)
|
public override GreenNode? GetSlot(int i)
|
||||||
{
|
{
|
||||||
return i switch
|
return i switch
|
||||||
{
|
{
|
||||||
0 => _statementList, 1 => _endOfFile, _ => null
|
0 => _body, 1 => _endOfFile, _ => null
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
;
|
||||||
|
116
Parser/Lowering/Lowerer.cs
Normal file
116
Parser/Lowering/Lowerer.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using Parser.Binding;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
using static Parser.Binding.BoundNodeFactory;
|
||||||
|
|
||||||
|
namespace Parser.Lowering
|
||||||
|
{
|
||||||
|
internal class Lowerer : BoundTreeRewriter
|
||||||
|
{
|
||||||
|
private int _labelNumber = 0;
|
||||||
|
|
||||||
|
private Lowerer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoundLabel GenerateLabel()
|
||||||
|
{
|
||||||
|
var name = $"Label{++_labelNumber}";
|
||||||
|
return new BoundLabel(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BoundStatement RewriteIfStatement(BoundIfStatement node)
|
||||||
|
{
|
||||||
|
// if cond
|
||||||
|
// body
|
||||||
|
// elseif cond1
|
||||||
|
// body1
|
||||||
|
// elseif cond2
|
||||||
|
// body2
|
||||||
|
// else
|
||||||
|
// body3
|
||||||
|
//
|
||||||
|
// gotoFalse cond Label1
|
||||||
|
// body
|
||||||
|
// goto LabelEnd
|
||||||
|
// Label1:
|
||||||
|
// gotoFalse cond1 Label2
|
||||||
|
// body1
|
||||||
|
// goto LabelEnd
|
||||||
|
// Label2:
|
||||||
|
// gotoFalse cond2 Label3
|
||||||
|
// body2
|
||||||
|
// goto LabelEnd
|
||||||
|
// Label3:
|
||||||
|
// body3
|
||||||
|
// LabelEnd:
|
||||||
|
|
||||||
|
var builder = ImmutableArray.CreateBuilder<BoundStatement>();
|
||||||
|
var numberOfLabelsNeeded = 1 + node.ElseifClauses.Length + (node.ElseClause is null ? 0 : 1);
|
||||||
|
var labels = new BoundLabel[numberOfLabelsNeeded];
|
||||||
|
for (var i = 0; i < numberOfLabelsNeeded; i++)
|
||||||
|
{
|
||||||
|
labels[i] = GenerateLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Add(GotoIfFalse(node.Syntax, node.Condition, labels[0]));
|
||||||
|
builder.Add(node.Body);
|
||||||
|
if (numberOfLabelsNeeded >= 2)
|
||||||
|
{
|
||||||
|
var counter = 0;
|
||||||
|
foreach (var elseifClause in node.ElseifClauses)
|
||||||
|
{
|
||||||
|
builder.Add(Goto(node.Syntax, labels[^1]));
|
||||||
|
builder.Add(LabelStatement(node.Syntax, labels[counter]));
|
||||||
|
counter++;
|
||||||
|
builder.Add(GotoIfFalse(node.Syntax, elseifClause.Condition, labels[counter]));
|
||||||
|
builder.Add(elseifClause.Body);
|
||||||
|
}
|
||||||
|
if (node.ElseClause is { } elseClause)
|
||||||
|
{
|
||||||
|
builder.Add(Goto(node.Syntax, labels[^1]));
|
||||||
|
builder.Add(LabelStatement(node.Syntax, labels[counter]));
|
||||||
|
builder.Add(elseClause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Add(LabelStatement(node.Syntax, labels[^1]));
|
||||||
|
return RewriteBlockStatement(Block(node.Syntax, builder.ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BoundBlockStatement Lower(BoundStatement statement)
|
||||||
|
{
|
||||||
|
var lowerer = new Lowerer();
|
||||||
|
var result = lowerer.RewriteStatement(statement);
|
||||||
|
var flatResult = lowerer.Flatten(result);
|
||||||
|
return flatResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BoundBlockStatement Flatten(BoundStatement statement)
|
||||||
|
{
|
||||||
|
var builder = ImmutableArray.CreateBuilder<BoundStatement>();
|
||||||
|
var stack = new Stack<BoundStatement>();
|
||||||
|
|
||||||
|
stack.Push(statement);
|
||||||
|
while (stack.Count() > 0)
|
||||||
|
{
|
||||||
|
var current = stack.Pop();
|
||||||
|
if (current is BoundBlockStatement block)
|
||||||
|
{
|
||||||
|
foreach (var s in block.Statements.Reverse())
|
||||||
|
{
|
||||||
|
stack.Push(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Add(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Block(statement.Syntax, builder.ToImmutable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,7 @@ namespace Parser.MFunctions
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MObject? Slash(MObject left, MObject right)
|
public static MObject? Slash(MObject left, MObject right)
|
||||||
{
|
{
|
||||||
if (left is MDoubleNumber { Value: var lValue }
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
@ -46,5 +47,59 @@ namespace Parser.MFunctions
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MObject? Greater(MObject left, MObject right)
|
||||||
|
{
|
||||||
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
|
&& right is MDoubleNumber { Value: var rValue })
|
||||||
|
{
|
||||||
|
return MObject.CreateLogical(lValue > rValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MObject? GreaterOrEquals(MObject left, MObject right)
|
||||||
|
{
|
||||||
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
|
&& right is MDoubleNumber { Value: var rValue })
|
||||||
|
{
|
||||||
|
return MObject.CreateLogical(lValue >= rValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MObject? Less(MObject left, MObject right)
|
||||||
|
{
|
||||||
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
|
&& right is MDoubleNumber { Value: var rValue })
|
||||||
|
{
|
||||||
|
return MObject.CreateLogical(lValue < rValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MObject? LessOrEquals(MObject left, MObject right)
|
||||||
|
{
|
||||||
|
if (left is MDoubleNumber { Value: var lValue }
|
||||||
|
&& right is MDoubleNumber { Value: var rValue })
|
||||||
|
{
|
||||||
|
return MObject.CreateLogical(lValue <= rValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MObject? Minus(MObject operand)
|
||||||
|
{
|
||||||
|
if (operand is MDoubleNumber { Value: var value })
|
||||||
|
{
|
||||||
|
return MObject.CreateDoubleNumber(-value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
Parser/Objects/MLogical.cs
Normal file
24
Parser/Objects/MLogical.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Parser.Objects
|
||||||
|
{
|
||||||
|
public class MLogical : MObject
|
||||||
|
{
|
||||||
|
public MLogical(bool value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Value { get; }
|
||||||
|
|
||||||
|
public static MLogical Create(bool value)
|
||||||
|
{
|
||||||
|
return new MLogical(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,5 +11,10 @@
|
|||||||
{
|
{
|
||||||
return MCharArray.Create(chars);
|
return MCharArray.Create(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MLogical CreateLogical(bool value)
|
||||||
|
{
|
||||||
|
return MLogical.Create(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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="SyntaxList" Name="statementList" />
|
<Field Type="BlockStatementSyntaxNode" Name="body" />
|
||||||
<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">
|
||||||
|
@ -3,7 +3,7 @@ namespace Parser
|
|||||||
{
|
{
|
||||||
public class FileSyntaxNode : SyntaxNode
|
public class FileSyntaxNode : SyntaxNode
|
||||||
{
|
{
|
||||||
private SyntaxNode? _statementList;
|
private SyntaxNode? _body;
|
||||||
internal FileSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position): base(parent, green, position)
|
internal FileSyntaxNode(SyntaxNode parent, Internal.GreenNode green, int position): base(parent, green, position)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -16,12 +16,12 @@ namespace Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SyntaxNodeOrTokenList StatementList
|
public BlockStatementSyntaxNode Body
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var red = this.GetRed(ref this._statementList!, 0);
|
var red = this.GetRed(ref this._body!, 0);
|
||||||
return red is null ? throw new System.Exception("statementList cannot be null.") : (SyntaxNodeOrTokenList)red;
|
return red is null ? throw new System.Exception("body cannot be null.") : (BlockStatementSyntaxNode)red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ namespace Parser
|
|||||||
{
|
{
|
||||||
return i switch
|
return i switch
|
||||||
{
|
{
|
||||||
0 => GetRed(ref _statementList!, 0), _ => null
|
0 => GetRed(ref _body!, 0), _ => null
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
;
|
||||||
|
@ -58,7 +58,7 @@ namespace Semantics
|
|||||||
|
|
||||||
public static MClass FromTree(FileSyntaxNode tree, string fileName)
|
public static MClass FromTree(FileSyntaxNode tree, string fileName)
|
||||||
{
|
{
|
||||||
var classDeclaration = tree.StatementList[0].AsNode() as ClassDeclarationSyntaxNode;
|
var classDeclaration = tree.Body.Statements[0].AsNode() as ClassDeclarationSyntaxNode;
|
||||||
if (classDeclaration == null)
|
if (classDeclaration == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -4,19 +4,26 @@ using System.IO;
|
|||||||
|
|
||||||
namespace cmi
|
namespace cmi
|
||||||
{
|
{
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
string fileName;
|
||||||
if (args.Length != 1)
|
if (args.Length != 1)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Usage: cmi <file.m>");
|
Console.Error.WriteLine("Usage: cmi <file.m>");
|
||||||
|
fileName = @"C:\repos\MParser\examples\helloworld\hello.m";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
var fileName = args[0];
|
{
|
||||||
|
fileName = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
var text = File.ReadAllText(fileName);
|
var text = File.ReadAllText(fileName);
|
||||||
var tree = SyntaxTree.Parse(text);
|
var tree = SyntaxTree.Parse(text);
|
||||||
var compilation = Compilation.Create(tree);
|
var compilation = Compilation.Create(tree);
|
||||||
|
TreeRenderer.RenderTree(tree);
|
||||||
if (tree.Diagnostics.Diagnostics.Count > 0)
|
if (tree.Diagnostics.Diagnostics.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var diagnostic in tree.Diagnostics.Diagnostics)
|
foreach (var diagnostic in tree.Diagnostics.Diagnostics)
|
||||||
@ -24,6 +31,7 @@ namespace cmi
|
|||||||
Console.ForegroundColor = ConsoleColor.DarkRed;
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
||||||
Console.WriteLine($"{diagnostic.Span}: {diagnostic.Message}");
|
Console.WriteLine($"{diagnostic.Span}: {diagnostic.Message}");
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
44
cmi/TreeRenderer.cs
Normal file
44
cmi/TreeRenderer.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using Parser;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace cmi
|
||||||
|
{
|
||||||
|
public class TreeRenderer
|
||||||
|
{
|
||||||
|
private static void RenderToken(SyntaxToken token, string indent, bool isLast)
|
||||||
|
{
|
||||||
|
Console.Write(indent + (isLast ? "└── " : "├── "));
|
||||||
|
Console.Write($"<{token.Kind}>");
|
||||||
|
Console.Write($" {token.Text}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RenderNode(SyntaxNode node, string indent, bool isLast)
|
||||||
|
{
|
||||||
|
Console.Write(indent);
|
||||||
|
Console.Write(isLast ? "└── " : "├── ");
|
||||||
|
Console.Write($"<{node.Kind}>");
|
||||||
|
Console.WriteLine();
|
||||||
|
var children = node.GetChildNodesAndTokens();
|
||||||
|
var last = children.Count - 1;
|
||||||
|
indent += isLast ? " " : "│ ";
|
||||||
|
for (var index = 0; index <= last; index++)
|
||||||
|
{
|
||||||
|
var child = children[index];
|
||||||
|
if (child.IsNode)
|
||||||
|
{
|
||||||
|
RenderNode(child.AsNode(), indent, index == last);
|
||||||
|
}
|
||||||
|
else if (child.IsToken)
|
||||||
|
{
|
||||||
|
RenderToken(child.AsToken(), indent, index == last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RenderTree(SyntaxTree tree)
|
||||||
|
{
|
||||||
|
RenderNode(tree.Root, "", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,11 +3,11 @@ y = 3;
|
|||||||
disp(x + y * y);
|
disp(x + y * y);
|
||||||
disp('Hello world!');
|
disp('Hello world!');
|
||||||
|
|
||||||
% x = 2 * 3;
|
x = 2 * 3;
|
||||||
% if x > 5
|
if x > 5
|
||||||
% y = 3;
|
y = 'Greater than 5';
|
||||||
% else
|
elseif x > 0
|
||||||
% y = 10;
|
y = 10;
|
||||||
% end
|
end
|
||||||
%
|
|
||||||
% disp(y);
|
disp(y);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user