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(
TokenKind.LessToken,
BoundBinaryOperatorKind.Less,
BoundBinaryOperatorKind.LessInt,
TypeSymbol.Int,
TypeSymbol.Boolean),
new BoundBinaryOperator(
TokenKind.PlusToken,
BoundBinaryOperatorKind.Plus,
BoundBinaryOperatorKind.PlusInt,
TypeSymbol.Int),
};

View File

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

View File

@ -437,7 +437,7 @@ namespace Parser.Binding
public ImmutableArray<BoundExpression> 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

View File

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

View File

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

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

View File

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