From 7f0889f0d4ce0db51e63124fd85485a0abcb9915 Mon Sep 17 00:00:00 2001 From: Alexander Luzgarev Date: Wed, 15 Jul 2020 17:22:48 +0200 Subject: [PATCH] Implement lowering --- ConsoleDemo/DumbWalker.cs | 2 +- ConsoleDemo/PrettyPrinter.cs | 2 +- ConsoleDemo/UsageGathering.cs | 2 +- MApplication/ColoringVisitor.cs | 2 +- Parser.Tests/MParserShould.cs | 8 +- Parser/Binding/Binder.cs | 80 +++++----- Parser/Binding/BoundLabel.cs | 17 +++ Parser/Binding/BoundNodeFactory.cs | 170 +++++++++++++++++++++ Parser/Binding/BoundNodeKind.cs | 6 +- Parser/Binding/BoundRoot.cs | 102 +++++++------ Parser/Binding/BoundTreeRewriter.cs | 89 ++++++----- Parser/Binding/BoundUnaryOperator.cs | 26 ++++ Parser/Binding/BoundUnaryOperatorKind.cs | 7 + Parser/Evaluator.cs | 99 +++++++++--- Parser/Internal/MParserGreen.cs | 2 +- Parser/Internal/SyntaxFactory.Generated.cs | 4 +- Parser/Internal/SyntaxNode.Generated.cs | 18 +-- Parser/Lowering/Lowerer.cs | 116 ++++++++++++++ Parser/MFunctions/MOperations.cs | 55 +++++++ Parser/Objects/MLogical.cs | 24 +++ Parser/Objects/MObject.cs | 5 + Parser/SyntaxDefinition.xml | 2 +- Parser/SyntaxNode.Generated.cs | 10 +- Semantics/GetClass.cs | 2 +- cmi/Program.cs | 12 +- cmi/TreeRenderer.cs | 44 ++++++ examples/helloworld/hello.m | 16 +- 27 files changed, 730 insertions(+), 192 deletions(-) create mode 100644 Parser/Binding/BoundLabel.cs create mode 100644 Parser/Binding/BoundNodeFactory.cs create mode 100644 Parser/Binding/BoundUnaryOperator.cs create mode 100644 Parser/Binding/BoundUnaryOperatorKind.cs create mode 100644 Parser/Lowering/Lowerer.cs create mode 100644 Parser/Objects/MLogical.cs create mode 100644 cmi/TreeRenderer.cs diff --git a/ConsoleDemo/DumbWalker.cs b/ConsoleDemo/DumbWalker.cs index fc3bd64..97a6a54 100644 --- a/ConsoleDemo/DumbWalker.cs +++ b/ConsoleDemo/DumbWalker.cs @@ -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) { diff --git a/ConsoleDemo/PrettyPrinter.cs b/ConsoleDemo/PrettyPrinter.cs index 3dab17f..1766ce4 100644 --- a/ConsoleDemo/PrettyPrinter.cs +++ b/ConsoleDemo/PrettyPrinter.cs @@ -8,7 +8,7 @@ namespace ProjectConsole { public override void VisitFile(FileSyntaxNode node) { - Visit(node.StatementList); + Visit(node.Body.Statements); OutputKeyword(node.EndOfFile); } diff --git a/ConsoleDemo/UsageGathering.cs b/ConsoleDemo/UsageGathering.cs index 9b227a6..6be20d1 100644 --- a/ConsoleDemo/UsageGathering.cs +++ b/ConsoleDemo/UsageGathering.cs @@ -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) { diff --git a/MApplication/ColoringVisitor.cs b/MApplication/ColoringVisitor.cs index ba9e4c7..0c6ae72 100644 --- a/MApplication/ColoringVisitor.cs +++ b/MApplication/ColoringVisitor.cs @@ -75,7 +75,7 @@ namespace MApplication public override void VisitFile(FileSyntaxNode node) { - Visit(node.StatementList); + Visit(node.Body.Statements); AddToken(node.EndOfFile, _scheme.Keyword); } diff --git a/Parser.Tests/MParserShould.cs b/Parser.Tests/MParserShould.cs index 91bd393..9a5a63e 100644 --- a/Parser.Tests/MParserShould.cs +++ b/Parser.Tests/MParserShould.cs @@ -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(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(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(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; diff --git a/Parser/Binding/Binder.cs b/Parser/Binding/Binder.cs index 2dd9d83..a042671 100644 --- a/Parser/Binding/Binder.cs +++ b/Parser/Binding/Binder.cs @@ -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 BindStatementList(SyntaxNodeOrTokenList list) + private IEnumerable BindStatementList(SyntaxNodeOrTokenList list) { - var builder = ImmutableArray.CreateBuilder(); 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 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()); - } } } diff --git a/Parser/Binding/BoundLabel.cs b/Parser/Binding/BoundLabel.cs new file mode 100644 index 0000000..577ce08 --- /dev/null +++ b/Parser/Binding/BoundLabel.cs @@ -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; + } + } +} diff --git a/Parser/Binding/BoundNodeFactory.cs b/Parser/Binding/BoundNodeFactory.cs new file mode 100644 index 0000000..f8b60ab --- /dev/null +++ b/Parser/Binding/BoundNodeFactory.cs @@ -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 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 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 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}."); + } + } +} diff --git a/Parser/Binding/BoundNodeKind.cs b/Parser/Binding/BoundNodeKind.cs index d75402f..4158dcd 100644 --- a/Parser/Binding/BoundNodeKind.cs +++ b/Parser/Binding/BoundNodeKind.cs @@ -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 diff --git a/Parser/Binding/BoundRoot.cs b/Parser/Binding/BoundRoot.cs index 6094363..5de782a 100644 --- a/Parser/Binding/BoundRoot.cs +++ b/Parser/Binding/BoundRoot.cs @@ -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 statements) + public BoundFile(SyntaxNode syntax, BoundStatement body) : base(syntax) { - Statements = statements; + Body = body; } - public ImmutableArray 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 elseifClauses, BoundElseClause? elseClause) + public BoundIfStatement(SyntaxNode syntax, BoundExpression condition, BoundStatement body, ImmutableArray elseifClauses, BoundStatement? elseClause) : base(syntax) { Condition = condition; @@ -145,11 +176,24 @@ namespace Parser.Binding public BoundExpression Condition { get; } public BoundStatement Body { get; } public ImmutableArray 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; - } } diff --git a/Parser/Binding/BoundTreeRewriter.cs b/Parser/Binding/BoundTreeRewriter.cs index 025dca8..83dd602 100644 --- a/Parser/Binding/BoundTreeRewriter.cs +++ b/Parser/Binding/BoundTreeRewriter.cs @@ -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(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(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(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) diff --git a/Parser/Binding/BoundUnaryOperator.cs b/Parser/Binding/BoundUnaryOperator.cs new file mode 100644 index 0000000..7006e1a --- /dev/null +++ b/Parser/Binding/BoundUnaryOperator.cs @@ -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); + } + } +} diff --git a/Parser/Binding/BoundUnaryOperatorKind.cs b/Parser/Binding/BoundUnaryOperatorKind.cs new file mode 100644 index 0000000..73d3fc2 --- /dev/null +++ b/Parser/Binding/BoundUnaryOperatorKind.cs @@ -0,0 +1,7 @@ +namespace Parser.Binding +{ + public enum BoundUnaryOperatorKind + { + Minus, + } +} diff --git a/Parser/Evaluator.cs b/Parser/Evaluator.cs index 2a233a7..d5714b8 100644 --- a/Parser/Evaluator.cs +++ b/Parser/Evaluator.cs @@ -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(); + 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) diff --git a/Parser/Internal/MParserGreen.cs b/Parser/Internal/MParserGreen.cs index e935f8d..2c2e250 100644 --- a/Parser/Internal/MParserGreen.cs +++ b/Parser/Internal/MParserGreen.cs @@ -1220,7 +1220,7 @@ namespace Parser.Internal public FileSyntaxNode ParseFile() { - var statementList = ParseStatementList(); + var statementList = ParseBlockStatement(); var endOfFileToken = EatToken(); return Factory.FileSyntax(statementList, endOfFileToken); } diff --git a/Parser/Internal/SyntaxFactory.Generated.cs b/Parser/Internal/SyntaxFactory.Generated.cs index 48981b9..826f4d1 100644 --- a/Parser/Internal/SyntaxFactory.Generated.cs +++ b/Parser/Internal/SyntaxFactory.Generated.cs @@ -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) diff --git a/Parser/Internal/SyntaxNode.Generated.cs b/Parser/Internal/SyntaxNode.Generated.cs index 014c271..149e4bc 100644 --- a/Parser/Internal/SyntaxNode.Generated.cs +++ b/Parser/Internal/SyntaxNode.Generated.cs @@ -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 } ; diff --git a/Parser/Lowering/Lowerer.cs b/Parser/Lowering/Lowerer.cs new file mode 100644 index 0000000..fbe3d05 --- /dev/null +++ b/Parser/Lowering/Lowerer.cs @@ -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(); + 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(); + var stack = new Stack(); + + 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()); + } + } +} diff --git a/Parser/MFunctions/MOperations.cs b/Parser/MFunctions/MOperations.cs index 7761f19..f454b3f 100644 --- a/Parser/MFunctions/MOperations.cs +++ b/Parser/MFunctions/MOperations.cs @@ -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; + } } } diff --git a/Parser/Objects/MLogical.cs b/Parser/Objects/MLogical.cs new file mode 100644 index 0000000..693c210 --- /dev/null +++ b/Parser/Objects/MLogical.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/Parser/Objects/MObject.cs b/Parser/Objects/MObject.cs index c76d9e6..702e985 100644 --- a/Parser/Objects/MObject.cs +++ b/Parser/Objects/MObject.cs @@ -11,5 +11,10 @@ { return MCharArray.Create(chars); } + + public static MLogical CreateLogical(bool value) + { + return MLogical.Create(value); + } } } \ No newline at end of file diff --git a/Parser/SyntaxDefinition.xml b/Parser/SyntaxDefinition.xml index d3baf5d..fcbc09a 100644 --- a/Parser/SyntaxDefinition.xml +++ b/Parser/SyntaxDefinition.xml @@ -1,7 +1,7 @@ - + diff --git a/Parser/SyntaxNode.Generated.cs b/Parser/SyntaxNode.Generated.cs index 9b60cbd..22a137a 100644 --- a/Parser/SyntaxNode.Generated.cs +++ b/Parser/SyntaxNode.Generated.cs @@ -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 } ; diff --git a/Semantics/GetClass.cs b/Semantics/GetClass.cs index 15cb673..49a38cd 100644 --- a/Semantics/GetClass.cs +++ b/Semantics/GetClass.cs @@ -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; diff --git a/cmi/Program.cs b/cmi/Program.cs index ec8f17d..ec5f7fe 100644 --- a/cmi/Program.cs +++ b/cmi/Program.cs @@ -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 "); + fileName = @"C:\repos\MParser\examples\helloworld\hello.m"; } - - var fileName = args[0]; + else + { + 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; } } diff --git a/cmi/TreeRenderer.cs b/cmi/TreeRenderer.cs new file mode 100644 index 0000000..e0d6871 --- /dev/null +++ b/cmi/TreeRenderer.cs @@ -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); + } + } +} diff --git a/examples/helloworld/hello.m b/examples/helloworld/hello.m index 9a79ec4..6b8f93b 100644 --- a/examples/helloworld/hello.m +++ b/examples/helloworld/hello.m @@ -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);