Implement lowering
This commit is contained in:
parent
652bd92f01
commit
7f0889f0d4
@ -169,7 +169,7 @@ namespace ConsoleDemo
|
||||
public override void VisitFile(FileSyntaxNode node)
|
||||
{
|
||||
_methodAssignments = new MethodAssignments();
|
||||
foreach (var nodeOrToken in node.StatementList)
|
||||
foreach (var nodeOrToken in node.Body.Statements)
|
||||
{
|
||||
if (nodeOrToken.IsToken)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ namespace ProjectConsole
|
||||
{
|
||||
public override void VisitFile(FileSyntaxNode node)
|
||||
{
|
||||
Visit(node.StatementList);
|
||||
Visit(node.Body.Statements);
|
||||
OutputKeyword(node.EndOfFile);
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ namespace ConsoleDemo
|
||||
public override void VisitFile(FileSyntaxNode node)
|
||||
{
|
||||
_methodAssignments = new MethodAssignments();
|
||||
foreach (var nodeOrToken in node.StatementList)
|
||||
foreach (var nodeOrToken in node.Body.Statements)
|
||||
{
|
||||
if (nodeOrToken.IsToken)
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ namespace MApplication
|
||||
|
||||
public override void VisitFile(FileSyntaxNode node)
|
||||
{
|
||||
Visit(node.StatementList);
|
||||
Visit(node.Body.Statements);
|
||||
AddToken(node.EndOfFile, _scheme.Keyword);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace Parser.Tests
|
||||
var text = "a = b";
|
||||
var sut = GetSut(text);
|
||||
var actual = sut.Parse();
|
||||
var assignment = actual.Root.StatementList[0].AsNode();
|
||||
var assignment = actual.Root.Body.Statements[0].AsNode();
|
||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||
if (assignment is null)
|
||||
{
|
||||
@ -35,7 +35,7 @@ namespace Parser.Tests
|
||||
var text = "2 + 3";
|
||||
var sut = GetSut(text);
|
||||
var actual = sut.Parse();
|
||||
var statement = actual.Root.StatementList[0].AsNode();
|
||||
var statement = actual.Root.Body.Statements[0].AsNode();
|
||||
Assert.IsType<ExpressionStatementSyntaxNode>(statement);
|
||||
if (statement is null)
|
||||
{
|
||||
@ -51,7 +51,7 @@ namespace Parser.Tests
|
||||
var text = "a = ";
|
||||
var sut = GetSut(text);
|
||||
var actual = sut.Parse();
|
||||
var assignment = actual.Root.StatementList[0].AsNode();
|
||||
var assignment = actual.Root.Body.Statements[0].AsNode();
|
||||
Assert.IsType<ExpressionStatementSyntaxNode>(assignment);
|
||||
if (assignment is null)
|
||||
{
|
||||
@ -77,7 +77,7 @@ namespace Parser.Tests
|
||||
var text = "2 + 3";
|
||||
var sut = GetSut(text);
|
||||
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 lhs = expression!.Lhs;
|
||||
var operation = expression.Operation;
|
||||
|
@ -1,24 +1,39 @@
|
||||
using Parser.Internal;
|
||||
using Parser.Lowering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
using static Parser.Binding.BoundNodeFactory;
|
||||
|
||||
namespace Parser.Binding
|
||||
{
|
||||
public class Binder
|
||||
{
|
||||
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)
|
||||
{
|
||||
var boundFile = BindFile(node.File);
|
||||
return new BoundRoot(node, boundFile);
|
||||
return Root(node, boundFile);
|
||||
}
|
||||
|
||||
private BoundFile BindFile(FileSyntaxNode node)
|
||||
{
|
||||
var statements = BindStatementList(node.StatementList);
|
||||
return new BoundFile(node, statements);
|
||||
var body = BindBlockStatement(node.Body);
|
||||
return File(node, body);
|
||||
}
|
||||
|
||||
private BoundStatement BindStatement(StatementSyntaxNode node)
|
||||
@ -27,6 +42,8 @@ namespace Parser.Binding
|
||||
{
|
||||
TokenKind.AbstractMethodDeclaration =>
|
||||
BindAbstractMethodDeclaration((AbstractMethodDeclarationSyntaxNode)node),
|
||||
TokenKind.BlockStatement =>
|
||||
BindBlockStatement((BlockStatementSyntaxNode)node),
|
||||
TokenKind.ClassDeclaration =>
|
||||
BindClassDeclaration((ClassDeclarationSyntaxNode)node),
|
||||
TokenKind.ConcreteMethodDeclaration =>
|
||||
@ -86,32 +103,27 @@ namespace Parser.Binding
|
||||
_ => 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 new BoundElseClause(node, body);
|
||||
return BindStatement(node.Body);
|
||||
}
|
||||
|
||||
private BoundBlockStatement BindBlockStatement(BlockStatementSyntaxNode node)
|
||||
{
|
||||
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()!);
|
||||
foreach (var statement in statements)
|
||||
{
|
||||
var boundStatement = BindStatement(statement);
|
||||
builder.Add(boundStatement);
|
||||
yield return BindStatement(statement);
|
||||
}
|
||||
|
||||
return builder.ToImmutable();
|
||||
}
|
||||
|
||||
private ImmutableArray<BoundExpression> BindExpressionList(SyntaxNodeOrTokenList list)
|
||||
@ -131,7 +143,7 @@ namespace Parser.Binding
|
||||
{
|
||||
var condition = BindExpression(node.Condition);
|
||||
var body = BindStatement(node.Body);
|
||||
return new BoundElseifClause(node, condition, body);
|
||||
return ElseifClause(node, condition, body);
|
||||
}
|
||||
|
||||
private BoundFunctionDeclaration BindFunctionDeclaration(FunctionDeclarationSyntaxNode node)
|
||||
@ -147,7 +159,7 @@ namespace Parser.Binding
|
||||
private BoundExpressionStatement BindExpressionStatement(ExpressionStatementSyntaxNode node)
|
||||
{
|
||||
var expression = BindExpression(node.Expression);
|
||||
return new BoundExpressionStatement(node, expression);
|
||||
return ExpressionStatement(node, expression);
|
||||
}
|
||||
|
||||
private BoundExpression BindExpression(ExpressionSyntaxNode node)
|
||||
@ -212,21 +224,14 @@ namespace Parser.Binding
|
||||
{
|
||||
var left = BindExpression(node.Lhs);
|
||||
var right = BindExpression(node.Rhs);
|
||||
return new BoundAssignmentExpression(node, left, right);
|
||||
return Assignment(node, left, right);
|
||||
}
|
||||
|
||||
private BoundBinaryOperationExpression BindBinaryOperationExpression(BinaryOperationExpressionSyntaxNode node)
|
||||
{
|
||||
var left = BindExpression(node.Lhs);
|
||||
var right = BindExpression(node.Rhs);
|
||||
var op = BindBinaryOperator(node.Operation);
|
||||
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}.");
|
||||
return BinaryOperation(node, left, node.Operation.Kind, right);
|
||||
}
|
||||
|
||||
private BoundCellArrayElementAccessExpression BindCellArrayElementAccessExpression(CellArrayElementAccessExpressionSyntaxNode node)
|
||||
@ -268,7 +273,7 @@ namespace Parser.Binding
|
||||
{
|
||||
var name = BindExpression(node.FunctionName);
|
||||
var arguments = BindExpressionList(node.Nodes);
|
||||
return new BoundFunctionCallExpression(node, name, arguments);
|
||||
return FunctionCall(node, name, arguments);
|
||||
}
|
||||
|
||||
private BoundIdentifierNameExpression BindIdentifierNameExpression(IdentifierNameExpressionSyntaxNode node)
|
||||
@ -299,27 +304,27 @@ namespace Parser.Binding
|
||||
private BoundNumberLiteralExpression BindNumberLiteralExpression(NumberLiteralExpressionSyntaxNode node)
|
||||
{
|
||||
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 new BoundParenthesizedExpression(node, expression);
|
||||
return BindExpression(node.Expression);
|
||||
}
|
||||
|
||||
private BoundStringLiteralExpression BindStringLiteralExpression(StringLiteralExpressionSyntaxNode node)
|
||||
{
|
||||
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();
|
||||
}
|
||||
@ -348,12 +353,5 @@ namespace Parser.Binding
|
||||
{
|
||||
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,
|
||||
ClassDeclaration,
|
||||
ConcreteMethodDeclaration,
|
||||
ConditionalGotoStatement,
|
||||
EmptyStatement,
|
||||
ExpressionStatement,
|
||||
ForStatement,
|
||||
FunctionDeclaration,
|
||||
GotoStatement,
|
||||
IfStatement,
|
||||
LabelStatement,
|
||||
SwitchStatement,
|
||||
TryCatchStatement,
|
||||
WhileStatement,
|
||||
@ -41,8 +44,7 @@
|
||||
NumberLiteralExpression,
|
||||
ParenthesizedExpression,
|
||||
StringLiteralExpression,
|
||||
UnaryPrefixOperationExpression,
|
||||
UnaryPostfixOperationExpression,
|
||||
UnaryOperationExpression,
|
||||
UnquotedStringLiteralExpression,
|
||||
|
||||
// Parts
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Parser.Binding
|
||||
{
|
||||
@ -18,13 +17,13 @@ namespace Parser.Binding
|
||||
|
||||
public class BoundFile : BoundNode
|
||||
{
|
||||
public BoundFile(SyntaxNode syntax, ImmutableArray<BoundStatement> statements)
|
||||
public BoundFile(SyntaxNode syntax, BoundStatement body)
|
||||
: base(syntax)
|
||||
{
|
||||
Statements = statements;
|
||||
Body = body;
|
||||
}
|
||||
|
||||
public ImmutableArray<BoundStatement> Statements { get; }
|
||||
public BoundStatement Body { get; }
|
||||
|
||||
public override BoundNodeKind Kind => BoundNodeKind.File;
|
||||
}
|
||||
@ -88,6 +87,25 @@ namespace Parser.Binding
|
||||
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 BoundEmptyStatement(SyntaxNode syntax)
|
||||
@ -131,9 +149,22 @@ namespace Parser.Binding
|
||||
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 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)
|
||||
{
|
||||
Condition = condition;
|
||||
@ -145,11 +176,24 @@ namespace Parser.Binding
|
||||
public BoundExpression Condition { get; }
|
||||
public BoundStatement Body { get; }
|
||||
public ImmutableArray<BoundElseifClause> ElseifClauses { get; }
|
||||
public BoundElseClause? ElseClause { get; }
|
||||
public BoundStatement? ElseClause { get; }
|
||||
|
||||
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 BoundSwitchStatement(SyntaxNode syntax)
|
||||
@ -378,19 +422,6 @@ namespace Parser.Binding
|
||||
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 BoundStringLiteralExpression(SyntaxNode syntax, string value)
|
||||
@ -403,24 +434,19 @@ namespace Parser.Binding
|
||||
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)
|
||||
{
|
||||
Op = op;
|
||||
Operand = operand;
|
||||
}
|
||||
|
||||
public override BoundNodeKind Kind => BoundNodeKind.UnaryPrefixOperationExpression;
|
||||
}
|
||||
public override BoundNodeKind Kind => BoundNodeKind.UnaryOperationExpression;
|
||||
|
||||
public class BoundUnaryPostfixOperationExpression : BoundExpression
|
||||
{
|
||||
public BoundUnaryPostfixOperationExpression(SyntaxNode syntax)
|
||||
: base(syntax)
|
||||
{
|
||||
}
|
||||
|
||||
public override BoundNodeKind Kind => BoundNodeKind.UnaryPostfixOperationExpression;
|
||||
public BoundUnaryOperator Op { get; }
|
||||
public BoundExpression Operand { get; }
|
||||
}
|
||||
|
||||
public class BoundUnquotedStringLiteralExpression : BoundExpression
|
||||
@ -446,16 +472,4 @@ namespace Parser.Binding
|
||||
public BoundStatement Body { get; }
|
||||
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.Collections.Immutable;
|
||||
using static Parser.Binding.BoundNodeFactory;
|
||||
|
||||
namespace Parser.Binding
|
||||
{
|
||||
@ -17,6 +18,8 @@ namespace Parser.Binding
|
||||
RewriteClassDeclaration((BoundClassDeclaration)node),
|
||||
BoundNodeKind.ConcreteMethodDeclaration =>
|
||||
RewriteConcreteMethodDeclaration((BoundConcreteMethodDeclaration)node),
|
||||
BoundNodeKind.ConditionalGotoStatement =>
|
||||
RewriteConditionalGotoStatement((BoundConditionalGotoStatement)node),
|
||||
BoundNodeKind.EmptyStatement =>
|
||||
RewriteEmptyStatement((BoundEmptyStatement)node),
|
||||
BoundNodeKind.ExpressionStatement =>
|
||||
@ -25,8 +28,12 @@ namespace Parser.Binding
|
||||
RewriteForStatement((BoundForStatement)node),
|
||||
BoundNodeKind.FunctionDeclaration =>
|
||||
RewriteFunctionDeclaration((BoundFunctionDeclaration)node),
|
||||
BoundNodeKind.GotoStatement =>
|
||||
RewriteGotoStatement((BoundGotoStatement)node),
|
||||
BoundNodeKind.IfStatement =>
|
||||
RewriteIfStatement((BoundIfStatement)node),
|
||||
BoundNodeKind.LabelStatement =>
|
||||
RewriteLabelStatement((BoundLabelStatement)node),
|
||||
BoundNodeKind.SwitchStatement =>
|
||||
RewriteSwitchStatement((BoundSwitchStatement)node),
|
||||
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)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@ -53,6 +76,11 @@ namespace Parser.Binding
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual BoundStatement RewriteLabelStatement(BoundLabelStatement node)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
public virtual BoundStatement RewriteIfStatement(BoundIfStatement node)
|
||||
{
|
||||
var condition = RewriteExpression(node.Condition);
|
||||
@ -65,7 +93,7 @@ namespace Parser.Binding
|
||||
if (oldClause != newClause && builder is null)
|
||||
{
|
||||
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]);
|
||||
}
|
||||
@ -74,11 +102,10 @@ namespace Parser.Binding
|
||||
{
|
||||
builder.Add(newClause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 &&
|
||||
body == node.Body &&
|
||||
elseIfClauses == node.ElseifClauses &&
|
||||
@ -87,18 +114,7 @@ namespace Parser.Binding
|
||||
return node;
|
||||
}
|
||||
|
||||
return new BoundIfStatement(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);
|
||||
return IfStatement(node.Syntax, condition, body, elseIfClauses, elseClause);
|
||||
}
|
||||
|
||||
public virtual BoundElseifClause RewriteElseifClause(BoundElseifClause node)
|
||||
@ -110,7 +126,7 @@ namespace Parser.Binding
|
||||
return node;
|
||||
}
|
||||
|
||||
return new BoundElseifClause(node.Syntax, condition, body);
|
||||
return ElseifClause(node.Syntax, condition, body);
|
||||
}
|
||||
|
||||
public virtual BoundStatement RewriteFunctionDeclaration(BoundFunctionDeclaration node)
|
||||
@ -131,7 +147,7 @@ namespace Parser.Binding
|
||||
return node;
|
||||
}
|
||||
|
||||
return new BoundExpressionStatement(node.Syntax, expression);
|
||||
return ExpressionStatement(node.Syntax, expression);
|
||||
}
|
||||
|
||||
public virtual BoundStatement RewriteEmptyStatement(BoundEmptyStatement node)
|
||||
@ -159,7 +175,7 @@ namespace Parser.Binding
|
||||
if (oldStatement != newStatement && builder is null)
|
||||
{
|
||||
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]);
|
||||
}
|
||||
@ -176,7 +192,7 @@ namespace Parser.Binding
|
||||
return node;
|
||||
}
|
||||
|
||||
return new BoundBlockStatement(node.Syntax, builder.MoveToImmutable());
|
||||
return Block(node.Syntax, builder.MoveToImmutable());
|
||||
}
|
||||
|
||||
public virtual BoundStatement RewriteAbstractMethodDeclaration(BoundAbstractMethodDeclaration node)
|
||||
@ -222,14 +238,10 @@ namespace Parser.Binding
|
||||
RewriteNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
||||
BoundNodeKind.NumberLiteralExpression =>
|
||||
RewriteNumberLiteralExpression((BoundNumberLiteralExpression)node),
|
||||
BoundNodeKind.ParenthesizedExpression =>
|
||||
RewriteParenthesizedExpression((BoundParenthesizedExpression)node),
|
||||
BoundNodeKind.StringLiteralExpression =>
|
||||
RewriteStringLiteralExpression((BoundStringLiteralExpression)node),
|
||||
BoundNodeKind.UnaryPrefixOperationExpression =>
|
||||
RewriteUnaryPrefixOperationExpression((BoundUnaryPrefixOperationExpression)node),
|
||||
BoundNodeKind.UnaryPostfixOperationExpression =>
|
||||
RewriteUnaryPostfixOperationExpression((BoundUnaryPostfixOperationExpression)node),
|
||||
BoundNodeKind.UnaryOperationExpression =>
|
||||
RewriteUnaryOperationExpression((BoundUnaryOperationExpression)node),
|
||||
BoundNodeKind.UnquotedStringLiteralExpression =>
|
||||
RewriteUnquotedStringLiteralExpression((BoundUnquotedStringLiteralExpression)node),
|
||||
_ =>
|
||||
@ -242,14 +254,10 @@ namespace Parser.Binding
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual BoundExpression RewriteUnaryPostfixOperationExpression(BoundUnaryPostfixOperationExpression node)
|
||||
public virtual BoundExpression RewriteUnaryOperationExpression(BoundUnaryOperationExpression node)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual BoundExpression RewriteUnaryPrefixOperationExpression(BoundUnaryPrefixOperationExpression node)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var operand = RewriteExpression(node.Operand);
|
||||
return new BoundUnaryOperationExpression(node.Syntax, node.Op, operand);
|
||||
}
|
||||
|
||||
public virtual BoundExpression RewriteStringLiteralExpression(BoundStringLiteralExpression node)
|
||||
@ -257,17 +265,6 @@ namespace Parser.Binding
|
||||
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)
|
||||
{
|
||||
return node;
|
||||
@ -309,7 +306,7 @@ namespace Parser.Binding
|
||||
if (oldArgument != newArgument && builder is null)
|
||||
{
|
||||
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]);
|
||||
}
|
||||
@ -326,7 +323,7 @@ namespace Parser.Binding
|
||||
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)
|
||||
@ -385,7 +382,7 @@ namespace Parser.Binding
|
||||
return node;
|
||||
}
|
||||
|
||||
return new BoundAssignmentExpression(node.Syntax, left, right);
|
||||
return Assignment(node.Syntax, left, right);
|
||||
}
|
||||
|
||||
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.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
@ -33,21 +32,77 @@ namespace Parser
|
||||
|
||||
private MObject? EvaluateFile(BoundFile root)
|
||||
{
|
||||
MObject? lastResult = null;
|
||||
foreach (var statement in root.Statements)
|
||||
return EvaluateStatement(root.Body);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private bool IsTruthyValue(MObject? expression)
|
||||
{
|
||||
if (expression is MLogical { Value: true })
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private MObject? EvaluateStatement(BoundStatement node)
|
||||
{
|
||||
return node.Kind switch
|
||||
{
|
||||
BoundNodeKind.AbstractMethodDeclaration =>
|
||||
EvaluateAbstractMethodDeclaration((BoundAbstractMethodDeclaration)node),
|
||||
BoundNodeKind.BlockStatement =>
|
||||
EvaluateBlockStatement((BoundBlockStatement)node),
|
||||
BoundNodeKind.ClassDeclaration =>
|
||||
EvaluateClassDeclaration((BoundClassDeclaration)node),
|
||||
BoundNodeKind.EmptyStatement =>
|
||||
@ -165,25 +220,16 @@ namespace Parser
|
||||
EvaluateNamedFunctionHandleExpression((BoundNamedFunctionHandleExpression)node),
|
||||
BoundNodeKind.NumberLiteralExpression =>
|
||||
EvaluateNumberLiteralExpression((BoundNumberLiteralExpression)node),
|
||||
BoundNodeKind.ParenthesizedExpression =>
|
||||
EvaluateParenthesizedExpression((BoundParenthesizedExpression)node),
|
||||
BoundNodeKind.StringLiteralExpression =>
|
||||
EvaluateStringLiteralExpression((BoundStringLiteralExpression)node),
|
||||
BoundNodeKind.UnaryPrefixOperationExpression =>
|
||||
EvaluateUnaryPrefixOperationExpression((BoundUnaryPrefixOperationExpression)node),
|
||||
BoundNodeKind.UnaryPostfixOperationExpression =>
|
||||
EvaluateUnaryPostfixOperationExpression((BoundUnaryPostfixOperationExpression)node),
|
||||
BoundNodeKind.UnaryOperationExpression =>
|
||||
EvaluateUnaryOperationExpression((BoundUnaryOperationExpression)node),
|
||||
BoundNodeKind.UnquotedStringLiteralExpression =>
|
||||
EvaluateUnquotedStringLiteralExpression((BoundUnquotedStringLiteralExpression)node),
|
||||
_ => throw new NotImplementedException($"Invalid expression kind '{node.Kind}'."),
|
||||
};
|
||||
}
|
||||
|
||||
private MObject? EvaluateParenthesizedExpression(BoundParenthesizedExpression node)
|
||||
{
|
||||
return EvaluateExpression(node.Expression);
|
||||
}
|
||||
|
||||
private MObject? EvaluateClassInvokation(BoundClassInvokationExpression node)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@ -199,11 +245,6 @@ namespace Parser
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private MObject? EvaluateUnaryPostfixOperationExpression(BoundUnaryPostfixOperationExpression node)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private MObject? EvaluateMemberAccess(BoundMemberAccessExpression node)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@ -338,6 +379,10 @@ namespace Parser
|
||||
BoundBinaryOperatorKind.Minus => MOperations.Minus(left, right),
|
||||
BoundBinaryOperatorKind.Star => MOperations.Star(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."),
|
||||
};
|
||||
}
|
||||
@ -347,9 +392,19 @@ namespace Parser
|
||||
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)
|
||||
|
@ -1220,7 +1220,7 @@ namespace Parser.Internal
|
||||
|
||||
public FileSyntaxNode ParseFile()
|
||||
{
|
||||
var statementList = ParseStatementList();
|
||||
var statementList = ParseBlockStatement();
|
||||
var endOfFileToken = EatToken();
|
||||
return Factory.FileSyntax(statementList, endOfFileToken);
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ namespace Parser.Internal
|
||||
{
|
||||
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)
|
||||
|
@ -3,22 +3,22 @@ namespace Parser.Internal
|
||||
{
|
||||
internal class FileSyntaxNode : SyntaxNode
|
||||
{
|
||||
internal readonly SyntaxList _statementList;
|
||||
internal readonly BlockStatementSyntaxNode _body;
|
||||
internal readonly SyntaxToken _endOfFile;
|
||||
internal FileSyntaxNode(SyntaxList statementList, SyntaxToken endOfFile): base(TokenKind.File)
|
||||
internal FileSyntaxNode(BlockStatementSyntaxNode body, SyntaxToken endOfFile): base(TokenKind.File)
|
||||
{
|
||||
Slots = 2;
|
||||
this.AdjustWidth(statementList);
|
||||
_statementList = statementList;
|
||||
this.AdjustWidth(body);
|
||||
_body = body;
|
||||
this.AdjustWidth(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;
|
||||
this.AdjustWidth(statementList);
|
||||
_statementList = statementList;
|
||||
this.AdjustWidth(body);
|
||||
_body = body;
|
||||
this.AdjustWidth(endOfFile);
|
||||
_endOfFile = endOfFile;
|
||||
}
|
||||
@ -30,14 +30,14 @@ namespace Parser.Internal
|
||||
|
||||
public override GreenNode SetDiagnostics(TokenDiagnostic[] diagnostics)
|
||||
{
|
||||
return new FileSyntaxNode(_statementList, _endOfFile, diagnostics);
|
||||
return new FileSyntaxNode(_body, _endOfFile, diagnostics);
|
||||
}
|
||||
|
||||
public override GreenNode? GetSlot(int i)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public static MObject? Slash(MObject left, MObject right)
|
||||
{
|
||||
if (left is MDoubleNumber { Value: var lValue }
|
||||
@ -46,5 +47,59 @@ namespace Parser.MFunctions
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public static MLogical CreateLogical(bool value)
|
||||
{
|
||||
return MLogical.Create(value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<?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">
|
||||
<Class Name="FileSyntaxNode" BaseClass="SyntaxNode" Kind="File">
|
||||
<Field Type="SyntaxList" Name="statementList" />
|
||||
<Field Type="BlockStatementSyntaxNode" Name="body" />
|
||||
<Field Type="SyntaxToken" Name="endOfFile" />
|
||||
</Class>
|
||||
<Class Name="BlockStatementSyntaxNode" BaseClass="StatementSyntaxNode" Kind="BlockStatement">
|
||||
|
@ -3,7 +3,7 @@ namespace Parser
|
||||
{
|
||||
public class FileSyntaxNode : SyntaxNode
|
||||
{
|
||||
private SyntaxNode? _statementList;
|
||||
private SyntaxNode? _body;
|
||||
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
|
||||
{
|
||||
var red = this.GetRed(ref this._statementList!, 0);
|
||||
return red is null ? throw new System.Exception("statementList cannot be null.") : (SyntaxNodeOrTokenList)red;
|
||||
var red = this.GetRed(ref this._body!, 0);
|
||||
return red is null ? throw new System.Exception("body cannot be null.") : (BlockStatementSyntaxNode)red;
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ namespace Parser
|
||||
{
|
||||
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)
|
||||
{
|
||||
var classDeclaration = tree.StatementList[0].AsNode() as ClassDeclarationSyntaxNode;
|
||||
var classDeclaration = tree.Body.Statements[0].AsNode() as ClassDeclarationSyntaxNode;
|
||||
if (classDeclaration == null)
|
||||
{
|
||||
return null;
|
||||
|
@ -4,19 +4,26 @@ using System.IO;
|
||||
|
||||
namespace cmi
|
||||
{
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
string fileName;
|
||||
if (args.Length != 1)
|
||||
{
|
||||
Console.Error.WriteLine("Usage: cmi <file.m>");
|
||||
fileName = @"C:\repos\MParser\examples\helloworld\hello.m";
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = args[0];
|
||||
}
|
||||
|
||||
var fileName = args[0];
|
||||
var text = File.ReadAllText(fileName);
|
||||
var tree = SyntaxTree.Parse(text);
|
||||
var compilation = Compilation.Create(tree);
|
||||
TreeRenderer.RenderTree(tree);
|
||||
if (tree.Diagnostics.Diagnostics.Count > 0)
|
||||
{
|
||||
foreach (var diagnostic in tree.Diagnostics.Diagnostics)
|
||||
@ -24,6 +31,7 @@ namespace cmi
|
||||
Console.ForegroundColor = ConsoleColor.DarkRed;
|
||||
Console.WriteLine($"{diagnostic.Span}: {diagnostic.Message}");
|
||||
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('Hello world!');
|
||||
|
||||
% x = 2 * 3;
|
||||
% if x > 5
|
||||
% y = 3;
|
||||
% else
|
||||
% y = 10;
|
||||
% end
|
||||
%
|
||||
% disp(y);
|
||||
x = 2 * 3;
|
||||
if x > 5
|
||||
y = 'Greater than 5';
|
||||
elseif x > 0
|
||||
y = 10;
|
||||
end
|
||||
|
||||
disp(y);
|
||||
|
Loading…
x
Reference in New Issue
Block a user