Implement lowering

This commit is contained in:
Alexander Luzgarev 2020-07-15 17:22:48 +02:00
parent 652bd92f01
commit 7f0889f0d4
27 changed files with 730 additions and 192 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

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

View File

@ -0,0 +1,7 @@
namespace Parser.Binding
{
public enum BoundUnaryOperatorKind
{
Minus,
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -11,5 +11,10 @@
{ {
return MCharArray.Create(chars); return MCharArray.Create(chars);
} }
public static MLogical CreateLogical(bool value)
{
return MLogical.Create(value);
}
} }
} }

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

View File

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

View File

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

View File

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

View File

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