From 6f6bbfaa1c4199c3c371893df02bb94020d40449 Mon Sep 17 00:00:00 2001 From: Alexander Luzgarev Date: Mon, 20 Jul 2020 14:52:14 +0200 Subject: [PATCH] Reimplement For in terms of While --- Parser/Binding/BoundBinaryOperator.cs | 4 +- Parser/Binding/BoundBinaryOperatorKind.cs | 2 + Parser/Binding/BoundRoot.cs | 2 +- Parser/Emitting/Emitter.cs | 56 ++++++++++++---- Parser/Lowering/Lowerer.cs | 79 +++++++++++------------ Parser/Objects/MDoubleMatrix.cs | 48 ++++++++++++++ Parser/Objects/MDoubleNumber.cs | 43 ------------ examples/helloworld/hello.m | 13 ++-- 8 files changed, 140 insertions(+), 107 deletions(-) create mode 100644 Parser/Objects/MDoubleMatrix.cs diff --git a/Parser/Binding/BoundBinaryOperator.cs b/Parser/Binding/BoundBinaryOperator.cs index fc614b3..772a085 100644 --- a/Parser/Binding/BoundBinaryOperator.cs +++ b/Parser/Binding/BoundBinaryOperator.cs @@ -8,12 +8,12 @@ namespace Parser.Binding { new BoundBinaryOperator( TokenKind.LessToken, - BoundBinaryOperatorKind.Less, + BoundBinaryOperatorKind.LessInt, TypeSymbol.Int, TypeSymbol.Boolean), new BoundBinaryOperator( TokenKind.PlusToken, - BoundBinaryOperatorKind.Plus, + BoundBinaryOperatorKind.PlusInt, TypeSymbol.Int), }; diff --git a/Parser/Binding/BoundBinaryOperatorKind.cs b/Parser/Binding/BoundBinaryOperatorKind.cs index cf43bf7..e4bd95d 100644 --- a/Parser/Binding/BoundBinaryOperatorKind.cs +++ b/Parser/Binding/BoundBinaryOperatorKind.cs @@ -25,5 +25,7 @@ Tilde, Caret, DotCaret, + LessInt, + PlusInt, } } diff --git a/Parser/Binding/BoundRoot.cs b/Parser/Binding/BoundRoot.cs index 5810d05..9c62a87 100644 --- a/Parser/Binding/BoundRoot.cs +++ b/Parser/Binding/BoundRoot.cs @@ -437,7 +437,7 @@ namespace Parser.Binding public ImmutableArray Arguments { get; } public override BoundNodeKind Kind => BoundNodeKind.FunctionCallExpression; - public override TypeSymbol Type => throw new System.NotImplementedException(); + public override TypeSymbol Type => TypeSymbol.MObject; } public class BoundTypedFunctionCallExpression : BoundExpression diff --git a/Parser/Emitting/Emitter.cs b/Parser/Emitting/Emitter.cs index 16a5015..4d1d8dd 100644 --- a/Parser/Emitting/Emitter.cs +++ b/Parser/Emitting/Emitter.cs @@ -360,7 +360,6 @@ namespace Parser.Emitting private void EmitFunction(LoweredFunction function, MethodDefinition methodDefinition) { - Console.WriteLine($"Emitting function '{function.Name}'."); var ilProcessor = methodDefinition.Body.GetILProcessor(); _labels.Clear(); @@ -467,7 +466,7 @@ namespace Parser.Emitting private void EmitConditionalGoto(BoundConditionalGotoStatement node, ILProcessor ilProcessor) { - var condition = ConvertExpression(node.Condition, TypeSymbol.Boolean); + var condition = TryConvertExpression(node.Condition, TypeSymbol.Boolean); if (condition is null) { throw new Exception("Cannot cast a condition in GOTO to boolean."); @@ -600,10 +599,30 @@ namespace Parser.Emitting private void EmitBinaryOperationExpression(BoundBinaryOperationExpression node, ILProcessor ilProcessor) { - var method = _binaryOperations[node.Op.Kind]; - EmitExpression(node.Left, ilProcessor); - EmitExpression(node.Right, ilProcessor); - ilProcessor.Emit(OpCodes.Call, method); + if (_binaryOperations.TryGetValue(node.Op.Kind, out var method)) + { + EmitExpression(node.Left, ilProcessor); + EmitExpression(node.Right, ilProcessor); + ilProcessor.Emit(OpCodes.Call, method); + } else + { + if (node.Op.Kind == BoundBinaryOperatorKind.LessInt) + { + EmitExpression(node.Left, ilProcessor); + EmitExpression(node.Right, ilProcessor); + ilProcessor.Emit(OpCodes.Clt); + } + else if (node.Op.Kind == BoundBinaryOperatorKind.PlusInt) + { + EmitExpression(node.Left, ilProcessor); + EmitExpression(node.Right, ilProcessor); + ilProcessor.Emit(OpCodes.Add); + } + else + { + throw new Exception($"Binary operation '{node.Op.Kind}' not implemented."); + } + } } private void EmitAssignmentExpression(BoundAssignmentExpression node, ILProcessor ilProcessor) @@ -615,9 +634,11 @@ namespace Parser.Emitting _ => throw new Exception($"Assignment to lvalue of kind {node.Left.Kind} is not supported."), }; - var rightType = node.Right.Type; - - var rewrittenRight = ConvertExpression(node.Right, leftType); + var rewrittenRight = TryConvertExpression(node.Right, leftType); + if (rewrittenRight is null) + { + throw new Exception($"Cannot convert an expression of type '{node.Right.Type}' to '{leftType}'."); + } if (node.Left.Kind == BoundNodeKind.IdentifierNameExpression) { @@ -634,6 +655,7 @@ namespace Parser.Emitting { var typedVariableExpression = (BoundTypedVariableExpression)node.Left; EmitExpression(rewrittenRight, ilProcessor); + ilProcessor.Emit(OpCodes.Dup); ilProcessor.Emit(OpCodes.Stloc, _typedLocals[typedVariableExpression.Variable]); } else @@ -664,7 +686,7 @@ namespace Parser.Emitting ilProcessor.Emit(OpCodes.Ldstr, node.Value); } - private BoundExpression? ConvertExpression(BoundExpression expression, TypeSymbol targetType) + private BoundExpression? TryConvertExpression(BoundExpression expression, TypeSymbol targetType) { var conversion = Conversion.Classify(expression.Type, targetType); if (!conversion.Exists) @@ -680,7 +702,12 @@ namespace Parser.Emitting { return BoundNodeFactory.Conversion(expression.Syntax, targetType, expression); } + } + private BoundExpression ConvertExpression(BoundExpression expression, TypeSymbol targetType) + { + return TryConvertExpression(expression, targetType) + ?? throw new Exception($"Conversion from '{expression.Type}' to '{targetType}' failed."); } private BoundExpression RewriteFunctionCall(BoundFunctionCallExpression node, TypedFunctionSymbol function) @@ -696,7 +723,7 @@ namespace Parser.Emitting { var argument = node.Arguments[i]; var parameter = function.Parameters[i]; - var rewrittenArgument = ConvertExpression(argument, parameter.Type); + var rewrittenArgument = TryConvertExpression(argument, parameter.Type); if (rewrittenArgument is null) { throw new NotImplementedException($"Argument number {i + 1} of function '{function.Name}' expects {parameter.Type}, but got {argument.Type}, and no conversion exists."); @@ -753,9 +780,10 @@ namespace Parser.Emitting throw new Exception("Multi-dimensional array slicing is not supported."); } - var typedVariableExpression = (BoundTypedVariableExpression)node.Name; - EmitTypedVariableExpression(typedVariableExpression, ilProcessor); - EmitExpression(node.Arguments[0], ilProcessor); + var typedVariableExpression = ConvertExpression((BoundTypedVariableExpression)node.Name, TypeSymbol.MObject); + EmitExpression(typedVariableExpression, ilProcessor); + var indexExpression = ConvertExpression(node.Arguments[0], TypeSymbol.MObject); + EmitExpression(indexExpression, ilProcessor); ilProcessor.Emit(OpCodes.Call, _arraySliceReference); } else diff --git a/Parser/Lowering/Lowerer.cs b/Parser/Lowering/Lowerer.cs index 7950fb9..9912f8e 100644 --- a/Parser/Lowering/Lowerer.cs +++ b/Parser/Lowering/Lowerer.cs @@ -1,4 +1,5 @@ using Parser.Binding; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -127,36 +128,23 @@ namespace Parser.Lowering // body // end // + // | + // | + // V + // // #array = expr // #length = len(#array) // #index = 0 - // i = #array(#index); - // LabelLoop: - // gotoFalse (#index < #length) LabelEnd - // body - // #index = #index + 1 - // goto LabelLoop - // LabelEnd: - var labelLoop = GenerateLabel(); - var labelEnd = GenerateLabel(); + // while #index < #length + // i = #array(#index); + // body + // #index = #index + 1 var localArray = GenerateTypedLocalVariable(TypeSymbol.MObject); var localLength = GenerateTypedLocalVariable(TypeSymbol.Int); var localIndex = GenerateTypedLocalVariable(TypeSymbol.Int); - return RewriteBlockStatement(Block( + var whileBody = Block( node.Syntax, - // #array = expr - TypedVariableDeclaration(node.Syntax, localArray, node.LoopedExpression), - // #length = len(#array) - TypedVariableDeclaration( - node.Syntax, - localLength, - FunctionCall( - node.Syntax, - Identifier(node.Syntax, "len"), - new[] { (BoundExpression)TypedVariableExpression(node.Syntax, localArray) }.ToImmutableArray())), - // #index = 0 - TypedVariableDeclaration(node.Syntax, localIndex, NumberDoubleLiteral(node.Syntax, 0.0)), - // i = #array(#index); + // i = #array(#index); ExpressionStatement( node.Syntax, Assignment( @@ -167,18 +155,7 @@ namespace Parser.Lowering TypedVariableExpression(node.Syntax, localArray), new[] { (BoundExpression)TypedVariableExpression(node.Syntax, localIndex) }.ToImmutableArray())), discardResult: true), - // LabelLoop: - LabelStatement(node.Syntax, labelLoop), - // gotoFalse (#index < #length) LabelEnd - GotoIfFalse( - node.Syntax, - BinaryOperation( - node.Syntax, - TypedVariableExpression(node.Syntax, localIndex), - BoundBinaryOperator.GetOperator(TokenKind.LessToken, TypeSymbol.Int, TypeSymbol.Int)!, - TypedVariableExpression(node.Syntax, localLength)), - labelEnd), - // body + // body node.Body, // #index = #index + 1; ExpressionStatement( @@ -191,11 +168,33 @@ namespace Parser.Lowering TypedVariableExpression(node.Syntax, localIndex), BoundBinaryOperator.GetOperator(TokenKind.PlusToken, TypeSymbol.Int, TypeSymbol.Int)!, NumberIntLiteral(node.Syntax, 1))), - discardResult: true), - // goto LabelLoop - Goto(node.Syntax, labelLoop), - // LabelEnd: - LabelStatement(node.Syntax, labelEnd))); + discardResult: true)); + + var result = Block( + node.Syntax, + // #array = expr + TypedVariableDeclaration(node.Syntax, localArray, node.LoopedExpression), + // #length = len(#array) + TypedVariableDeclaration( + node.Syntax, + localLength, + FunctionCall( + node.Syntax, + Identifier(node.Syntax, "len"), + new[] { (BoundExpression)TypedVariableExpression(node.Syntax, localArray) }.ToImmutableArray())), + // #index = 0 + TypedVariableDeclaration(node.Syntax, localIndex, NumberIntLiteral(node.Syntax, 0)), + // while #index < #length + // whileBody + WhileStatement( + node.Syntax, + BinaryOperation( + node.Syntax, + TypedVariableExpression(node.Syntax, localIndex), + BoundBinaryOperator.GetOperator(TokenKind.LessToken, TypeSymbol.Int, TypeSymbol.Int)!, + TypedVariableExpression(node.Syntax, localLength)), + whileBody)); + return RewriteBlockStatement(result); } public static BoundBlockStatement Lower(BoundStatement statement) diff --git a/Parser/Objects/MDoubleMatrix.cs b/Parser/Objects/MDoubleMatrix.cs new file mode 100644 index 0000000..6fa38e1 --- /dev/null +++ b/Parser/Objects/MDoubleMatrix.cs @@ -0,0 +1,48 @@ +using System.Text; + +namespace Parser.Objects +{ + public class MDoubleMatrix : MObject + { + private MDoubleMatrix(double[,] matrix) + { + Matrix = matrix; + RowCount = matrix.GetLength(0); + ColumnCount = matrix.GetLength(1); + } + + public double[,] Matrix { get; } + + public int RowCount { get; } + + public int ColumnCount { get; } + + public ref double this[int i, int j] => ref Matrix[i, j]; + + public ref double this[int i] => ref Matrix[i % RowCount, i / RowCount]; + + public override string ToString() + { + var sb = new StringBuilder(); + for (var i = 0; i < RowCount; i++) + { + for (var j = 0; j < ColumnCount; j++) + { + if (j > 0) + { + sb.Append(' '); + } + sb.Append(Matrix[i, j]); + } + + sb.AppendLine(); + } + return sb.ToString(); + } + + public static MDoubleMatrix Create(double[,] matrix) + { + return new MDoubleMatrix(matrix); + } + } +} \ No newline at end of file diff --git a/Parser/Objects/MDoubleNumber.cs b/Parser/Objects/MDoubleNumber.cs index b7bd105..bb7f76f 100644 --- a/Parser/Objects/MDoubleNumber.cs +++ b/Parser/Objects/MDoubleNumber.cs @@ -1,50 +1,7 @@ using System.Globalization; -using System.Text; namespace Parser.Objects { - public class MDoubleMatrix : MObject - { - private MDoubleMatrix(double[,] matrix) - { - Matrix = matrix; - } - - public double[,] Matrix { get; } - - public int RowCount { get; } - - public int ColumnCount { get; } - - public ref double this[int i, int j] => ref Matrix[i, j]; - - public ref double this[int i] => ref Matrix[i % RowCount, i / RowCount]; - - public override string ToString() - { - var sb = new StringBuilder(); - for (var i = 0; i < RowCount; i++) - { - for (var j = 0; j < ColumnCount; j++) - { - if (j > 0) - { - sb.Append(' '); - } - sb.Append(Matrix[i, j]); - } - - sb.AppendLine(); - } - return sb.ToString(); - } - - public static MDoubleMatrix Create(double[,] matrix) - { - return new MDoubleMatrix(matrix); - } - } - public class MDoubleNumber : MObject { private MDoubleNumber(double value) diff --git a/examples/helloworld/hello.m b/examples/helloworld/hello.m index 22a2fa2..1a46c7e 100644 --- a/examples/helloworld/hello.m +++ b/examples/helloworld/hello.m @@ -5,16 +5,15 @@ f(x); x = 3; f(x); -i = 1; -while i <= 10 - disp(i); - i = i + 1; -end - -% for i = 1:10 +% i = 1; +% while i <= 10 % disp(i); +% i = i + 1; % end +for i = 1:10 + disp(i); +end function f(x) disp('X was');