Beispiel #1
0
        /// <summary>
        /// Convert an expression that yields a value and assign that value into <paramref name="resultPlace"/>.
        /// </summary>
        private void ConvertIntoPlace(IExpression expression, Place resultPlace)
        {
            switch (expression)
            {
            default:
                throw ExhaustiveMatch.Failed(expression);

            case ILoopExpression _:
            case IWhileExpression _:
            case IForeachExpression _:
            case IReturnExpression _:
            case IBreakExpression _:
            case INextExpression _:
            case IIfExpression _:
            case IUnsafeExpression _:
            case IBlockExpression _:
            case INoneLiteralExpression _:
                throw new NotImplementedException($"ConvertIntoPlace({expression.GetType().Name}, Place) Not Implemented.");

            case ISelfExpression exp:
            {
                // This occurs when the source code contains a simple assignment like `x = self`
                var symbol   = exp.ReferencedSymbol;
                var variable = graph.VariableFor(symbol).Reference(exp.Span);
                currentBlock !.Add(new AssignmentInstruction(resultPlace, variable, exp.Span, CurrentScope));
            }
            break;

            case IImplicitOptionalConversionExpression exp:
            {
                var operand = ConvertToOperand(exp.Expression);
                currentBlock !.Add(new SomeInstruction(resultPlace, exp.ConvertToType, operand, exp.Span, CurrentScope));
            }
            break;

            case IAssignmentExpression exp:
                throw new NotImplementedException("Assignments don't have a result");

            case INameExpression exp:
            {
                // This occurs when the source code contains a simple assignment like `x = y`
                var symbol   = exp.ReferencedSymbol;
                var variable = graph.VariableFor(symbol).Reference(exp.Span);
                currentBlock !.Add(new AssignmentInstruction(resultPlace, variable, exp.Span, CurrentScope));
            }
            break;

            case IBorrowExpression exp:
                ConvertIntoPlace(exp.Referent, resultPlace);
                break;

            case IShareExpression exp:
                ConvertIntoPlace(exp.Referent, resultPlace);
                break;

            case IMoveExpression exp:
                ConvertIntoPlace(exp.Referent, resultPlace);
                break;

            case IImplicitImmutabilityConversionExpression exp:
                ConvertIntoPlace(exp.Expression, resultPlace);
                break;

            case IBinaryOperatorExpression exp:
            {
                var resultType   = exp.DataType.Assigned().Known();
                var operandType  = exp.LeftOperand.DataType.Assigned().Known();
                var leftOperand  = ConvertToOperand(exp.LeftOperand);
                var rightOperand = ConvertToOperand(exp.RightOperand);
                switch (exp.Operator)
                {
                default:
                    throw ExhaustiveMatch.Failed(expression);

                case BinaryOperator.DotDot:
                case BinaryOperator.LessThanDotDot:
                case BinaryOperator.DotDotLessThan:
                case BinaryOperator.LessThanDotDotLessThan:
                    throw new NotImplementedException("Range operator control flow not implemented");

                    #region Logical Operators
                case BinaryOperator.And:
                    // TODO handle calls to overloaded operators
                    // TODO handle short circuiting if needed
                    currentBlock !.Add(new BooleanLogicInstruction(resultPlace, And,
                                                                   leftOperand, rightOperand, CurrentScope));
                    break;

                case BinaryOperator.Or:
                    // TODO handle calls to overloaded operators
                    // TODO handle short circuiting if needed
                    currentBlock !.Add(new BooleanLogicInstruction(resultPlace, Or,
                                                                   leftOperand, rightOperand, CurrentScope));
                    break;

                    #endregion
                    #region Binary Math Operators
                case BinaryOperator.Plus:
                    currentBlock !.Add(new NumericInstruction(resultPlace, Add,
                                                              (NumericType)resultType, leftOperand, rightOperand, CurrentScope));
                    break;

                case BinaryOperator.Minus:
                    currentBlock !.Add(new NumericInstruction(resultPlace, Subtract,
                                                              (NumericType)resultType, leftOperand, rightOperand, CurrentScope));
                    break;

                case BinaryOperator.Asterisk:
                    currentBlock !.Add(new NumericInstruction(resultPlace, Multiply,
                                                              (NumericType)resultType, leftOperand, rightOperand, CurrentScope));
                    break;

                case BinaryOperator.Slash:
                    currentBlock !.Add(new NumericInstruction(resultPlace, Divide,
                                                              (NumericType)resultType, leftOperand, rightOperand, CurrentScope));
                    break;

                    #endregion
                    #region Comparisons
                case BinaryOperator.EqualsEquals:
                    currentBlock !.Add(new CompareInstruction(resultPlace, Equal,
                                                              (NumericType)operandType, leftOperand, rightOperand, CurrentScope));
                    break;

                case BinaryOperator.NotEqual:
                    currentBlock !.Add(new CompareInstruction(resultPlace, NotEqual,
                                                              (NumericType)operandType, leftOperand, rightOperand, CurrentScope));
                    break;

                case BinaryOperator.LessThan:
                    currentBlock !.Add(new CompareInstruction(resultPlace, LessThan,
                                                              (NumericType)operandType, leftOperand, rightOperand, CurrentScope));
                    break;

                case BinaryOperator.LessThanOrEqual:
                    currentBlock !.Add(new CompareInstruction(resultPlace, LessThanOrEqual,
                                                              (NumericType)operandType, leftOperand, rightOperand, CurrentScope));
                    break;

                case BinaryOperator.GreaterThan:
                    currentBlock !.Add(new CompareInstruction(resultPlace, GreaterThan,
                                                              (NumericType)operandType, leftOperand, rightOperand, CurrentScope));
                    break;

                case BinaryOperator.GreaterThanOrEqual:
                    currentBlock !.Add(new CompareInstruction(resultPlace, GreaterThanOrEqual,
                                                              (NumericType)operandType, leftOperand, rightOperand, CurrentScope));
                    break;
                    #endregion Comparisons
                }
            }
            break;

            case IUnaryOperatorExpression exp:
            {
                var type    = exp.DataType.Assigned().Known();
                var operand = ConvertToOperand(exp.Operand);
                switch (exp.Operator)
                {
                default:
                    throw ExhaustiveMatch.Failed(expression);

                case UnaryOperator.Not:
                case UnaryOperator.Plus:         // TODO don't even allow unary plus in IL or AST, it is a noop
                    throw new NotImplementedException($"ConvertToOperand({expression.GetType().Name}, Place) Not Implemented for {exp.Operator}.");

                case UnaryOperator.Minus:
                    currentBlock !.Add(new NegateInstruction(resultPlace, (NumericType)type, operand, exp.Span, CurrentScope));
                    break;
                }
            }
            break;

            case IFieldAccessExpression exp:
            {
                var context = ConvertToOperand(exp.Context);
                var field   = exp.ReferencedSymbol;
                currentBlock !.Add(new FieldAccessInstruction(resultPlace, context, field, exp.Span, CurrentScope));
            }
            break;

            case IFunctionInvocationExpression exp:
            {
                var functionName = exp.ReferencedSymbol;
                var args         = exp.Arguments.Select(ConvertToOperand).ToFixedList();
                currentBlock !.Add(CallInstruction.ForFunction(resultPlace, functionName, args, exp.Span, CurrentScope));
            }
            break;

            case IMethodInvocationExpression exp:
            {
                var methodName = exp.ReferencedSymbol;
                var target     = ConvertToOperand(exp.Context);
                var args       = exp.Arguments.Select(ConvertToOperand).ToFixedList();
                if (exp.Context.DataType is ReferenceType)
                {
                    currentBlock !.Add(new CallVirtualInstruction(resultPlace, target, methodName, args, exp.Span, CurrentScope));
                }
                else
                {
                    currentBlock !.Add(CallInstruction.ForMethod(resultPlace, target, methodName, args, exp.Span, CurrentScope));
                }
            }
            break;

            case INewObjectExpression exp:
            {
                var constructor     = exp.ReferencedSymbol;
                var args            = exp.Arguments.Select(ConvertToOperand).ToFixedList();
                var constructedType = (ObjectType)exp.DataType.Known();
                currentBlock !.Add(new NewObjectInstruction(resultPlace, constructor, constructedType, args, exp.Span, CurrentScope));
            }
            break;

            case IStringLiteralExpression exp:
                currentBlock !.Add(new LoadStringInstruction(resultPlace, exp.Value, exp.Span, CurrentScope));
                break;

            case IBoolLiteralExpression exp:
                currentBlock !.Add(new LoadBoolInstruction(resultPlace, exp.Value, exp.Span, CurrentScope));
                break;

            case IImplicitNumericConversionExpression exp:
            {
                if (exp.Expression.DataType.Assigned().Known() is IntegerConstantType constantType)
                {
                    currentBlock !.Add(new LoadIntegerInstruction(resultPlace, constantType.Value,
                                                                  (IntegerType)exp.DataType.Assigned().Known(),
                                                                  exp.Span, CurrentScope));
                }
                else
                {
                    currentBlock !.Add(new ConvertInstruction(resultPlace, ConvertToOperand(exp.Expression),
                                                              (NumericType)exp.Expression.DataType.Assigned().Known(), exp.ConvertToType,
                                                              exp.Span, CurrentScope));
                }
            }
            break;

            case IIntegerLiteralExpression exp:
                throw new InvalidOperationException(
                          "Integer literals should have an implicit conversion around them");

            case IImplicitNoneConversionExpression exp:
                currentBlock !.Add(new LoadNoneInstruction(resultPlace, exp.ConvertToType, exp.Span, CurrentScope));
                break;
            }
        }