Reimplement For in terms of While

This commit is contained in:
Alexander Luzgarev 2020-07-20 14:52:14 +02:00
parent f66013cf12
commit 6f6bbfaa1c
8 changed files with 140 additions and 107 deletions

View File

@ -8,12 +8,12 @@ namespace Parser.Binding
{ {
new BoundBinaryOperator( new BoundBinaryOperator(
TokenKind.LessToken, TokenKind.LessToken,
BoundBinaryOperatorKind.Less, BoundBinaryOperatorKind.LessInt,
TypeSymbol.Int, TypeSymbol.Int,
TypeSymbol.Boolean), TypeSymbol.Boolean),
new BoundBinaryOperator( new BoundBinaryOperator(
TokenKind.PlusToken, TokenKind.PlusToken,
BoundBinaryOperatorKind.Plus, BoundBinaryOperatorKind.PlusInt,
TypeSymbol.Int), TypeSymbol.Int),
}; };

View File

@ -25,5 +25,7 @@
Tilde, Tilde,
Caret, Caret,
DotCaret, DotCaret,
LessInt,
PlusInt,
} }
} }

View File

@ -437,7 +437,7 @@ namespace Parser.Binding
public ImmutableArray<BoundExpression> Arguments { get; } public ImmutableArray<BoundExpression> Arguments { get; }
public override BoundNodeKind Kind => BoundNodeKind.FunctionCallExpression; public override BoundNodeKind Kind => BoundNodeKind.FunctionCallExpression;
public override TypeSymbol Type => throw new System.NotImplementedException(); public override TypeSymbol Type => TypeSymbol.MObject;
} }
public class BoundTypedFunctionCallExpression : BoundExpression public class BoundTypedFunctionCallExpression : BoundExpression

View File

@ -360,7 +360,6 @@ namespace Parser.Emitting
private void EmitFunction(LoweredFunction function, MethodDefinition methodDefinition) private void EmitFunction(LoweredFunction function, MethodDefinition methodDefinition)
{ {
Console.WriteLine($"Emitting function '{function.Name}'.");
var ilProcessor = methodDefinition.Body.GetILProcessor(); var ilProcessor = methodDefinition.Body.GetILProcessor();
_labels.Clear(); _labels.Clear();
@ -467,7 +466,7 @@ namespace Parser.Emitting
private void EmitConditionalGoto(BoundConditionalGotoStatement node, ILProcessor ilProcessor) 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) if (condition is null)
{ {
throw new Exception("Cannot cast a condition in GOTO to boolean."); 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) private void EmitBinaryOperationExpression(BoundBinaryOperationExpression node, ILProcessor ilProcessor)
{ {
var method = _binaryOperations[node.Op.Kind]; if (_binaryOperations.TryGetValue(node.Op.Kind, out var method))
{
EmitExpression(node.Left, ilProcessor); EmitExpression(node.Left, ilProcessor);
EmitExpression(node.Right, ilProcessor); EmitExpression(node.Right, ilProcessor);
ilProcessor.Emit(OpCodes.Call, method); 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) 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."), _ => throw new Exception($"Assignment to lvalue of kind {node.Left.Kind} is not supported."),
}; };
var rightType = node.Right.Type; var rewrittenRight = TryConvertExpression(node.Right, leftType);
if (rewrittenRight is null)
var rewrittenRight = ConvertExpression(node.Right, leftType); {
throw new Exception($"Cannot convert an expression of type '{node.Right.Type}' to '{leftType}'.");
}
if (node.Left.Kind == BoundNodeKind.IdentifierNameExpression) if (node.Left.Kind == BoundNodeKind.IdentifierNameExpression)
{ {
@ -634,6 +655,7 @@ namespace Parser.Emitting
{ {
var typedVariableExpression = (BoundTypedVariableExpression)node.Left; var typedVariableExpression = (BoundTypedVariableExpression)node.Left;
EmitExpression(rewrittenRight, ilProcessor); EmitExpression(rewrittenRight, ilProcessor);
ilProcessor.Emit(OpCodes.Dup);
ilProcessor.Emit(OpCodes.Stloc, _typedLocals[typedVariableExpression.Variable]); ilProcessor.Emit(OpCodes.Stloc, _typedLocals[typedVariableExpression.Variable]);
} }
else else
@ -664,7 +686,7 @@ namespace Parser.Emitting
ilProcessor.Emit(OpCodes.Ldstr, node.Value); 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); var conversion = Conversion.Classify(expression.Type, targetType);
if (!conversion.Exists) if (!conversion.Exists)
@ -680,7 +702,12 @@ namespace Parser.Emitting
{ {
return BoundNodeFactory.Conversion(expression.Syntax, targetType, expression); 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) private BoundExpression RewriteFunctionCall(BoundFunctionCallExpression node, TypedFunctionSymbol function)
@ -696,7 +723,7 @@ namespace Parser.Emitting
{ {
var argument = node.Arguments[i]; var argument = node.Arguments[i];
var parameter = function.Parameters[i]; var parameter = function.Parameters[i];
var rewrittenArgument = ConvertExpression(argument, parameter.Type); var rewrittenArgument = TryConvertExpression(argument, parameter.Type);
if (rewrittenArgument is null) 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."); 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."); throw new Exception("Multi-dimensional array slicing is not supported.");
} }
var typedVariableExpression = (BoundTypedVariableExpression)node.Name; var typedVariableExpression = ConvertExpression((BoundTypedVariableExpression)node.Name, TypeSymbol.MObject);
EmitTypedVariableExpression(typedVariableExpression, ilProcessor); EmitExpression(typedVariableExpression, ilProcessor);
EmitExpression(node.Arguments[0], ilProcessor); var indexExpression = ConvertExpression(node.Arguments[0], TypeSymbol.MObject);
EmitExpression(indexExpression, ilProcessor);
ilProcessor.Emit(OpCodes.Call, _arraySliceReference); ilProcessor.Emit(OpCodes.Call, _arraySliceReference);
} }
else else

View File

@ -1,4 +1,5 @@
using Parser.Binding; using Parser.Binding;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
@ -127,35 +128,22 @@ namespace Parser.Lowering
// body // body
// end // end
// //
// |
// |
// V
//
// #array = expr // #array = expr
// #length = len(#array) // #length = len(#array)
// #index = 0 // #index = 0
// while #index < #length
// i = #array(#index); // i = #array(#index);
// LabelLoop:
// gotoFalse (#index < #length) LabelEnd
// body // body
// #index = #index + 1 // #index = #index + 1
// goto LabelLoop
// LabelEnd:
var labelLoop = GenerateLabel();
var labelEnd = GenerateLabel();
var localArray = GenerateTypedLocalVariable(TypeSymbol.MObject); var localArray = GenerateTypedLocalVariable(TypeSymbol.MObject);
var localLength = GenerateTypedLocalVariable(TypeSymbol.Int); var localLength = GenerateTypedLocalVariable(TypeSymbol.Int);
var localIndex = GenerateTypedLocalVariable(TypeSymbol.Int); var localIndex = GenerateTypedLocalVariable(TypeSymbol.Int);
return RewriteBlockStatement(Block( var whileBody = Block(
node.Syntax, 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( ExpressionStatement(
node.Syntax, node.Syntax,
@ -167,17 +155,6 @@ namespace Parser.Lowering
TypedVariableExpression(node.Syntax, localArray), TypedVariableExpression(node.Syntax, localArray),
new[] { (BoundExpression)TypedVariableExpression(node.Syntax, localIndex) }.ToImmutableArray())), new[] { (BoundExpression)TypedVariableExpression(node.Syntax, localIndex) }.ToImmutableArray())),
discardResult: true), 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, node.Body,
// #index = #index + 1; // #index = #index + 1;
@ -191,11 +168,33 @@ namespace Parser.Lowering
TypedVariableExpression(node.Syntax, localIndex), TypedVariableExpression(node.Syntax, localIndex),
BoundBinaryOperator.GetOperator(TokenKind.PlusToken, TypeSymbol.Int, TypeSymbol.Int)!, BoundBinaryOperator.GetOperator(TokenKind.PlusToken, TypeSymbol.Int, TypeSymbol.Int)!,
NumberIntLiteral(node.Syntax, 1))), NumberIntLiteral(node.Syntax, 1))),
discardResult: true), discardResult: true));
// goto LabelLoop
Goto(node.Syntax, labelLoop), var result = Block(
// LabelEnd: node.Syntax,
LabelStatement(node.Syntax, labelEnd))); // #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) public static BoundBlockStatement Lower(BoundStatement statement)

View File

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

View File

@ -1,50 +1,7 @@
using System.Globalization; using System.Globalization;
using System.Text;
namespace Parser.Objects 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 public class MDoubleNumber : MObject
{ {
private MDoubleNumber(double value) private MDoubleNumber(double value)

View File

@ -5,16 +5,15 @@ f(x);
x = 3; x = 3;
f(x); f(x);
i = 1; % i = 1;
while i <= 10 % while i <= 10
disp(i);
i = i + 1;
end
% for i = 1:10
% disp(i); % disp(i);
% i = i + 1;
% end % end
for i = 1:10
disp(i);
end
function f(x) function f(x)
disp('X was'); disp('X was');